Skip to content

Commit 98944e0

Browse files
committed
added grid bfs, fixed java dfs
1 parent 86a73c6 commit 98944e0

File tree

5 files changed

+186
-20
lines changed

5 files changed

+186
-20
lines changed

src/java/sequential/graph/bfs/BUILD

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,10 @@ java_binary(
22
name = "bfs",
33
main_class = "sequential.graph.bfs.BreadthFirstTraversal",
44
srcs = glob(["*.java"]),
5+
)
6+
7+
java_binary(
8+
name = "bfs_grid",
9+
main_class = "sequential.graph.bfs.GridBreadthFirstTraversal",
10+
srcs = glob(["*.java"]),
511
)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package sequential.graph.bfs;
2+
3+
import java.util.ArrayDeque;
4+
import java.util.ArrayList;
5+
import java.util.Collection;
6+
7+
8+
public class GridBreadthFirstTraversal {
9+
10+
private final static int[] ROW_DIRECTIONS = {0, -1, 0, 1};
11+
private final static int[] COL_DIRECTIONS = {-1, 0, 1, 0};
12+
13+
private static class Vertex {
14+
final int row, col;
15+
16+
public Vertex(int row, int col) {
17+
this.row = row;
18+
this.col = col;
19+
}
20+
}
21+
22+
23+
public static <T> Collection<T> bfs(T[][] graph, int rootRow, int rootCol) {
24+
if (!isGraphValid(graph, rootRow, rootCol)) throw new IllegalArgumentException("Invalid graph.");
25+
26+
int rows = graph.length;
27+
int cols = graph[0].length;
28+
29+
var explored = new boolean[rows][cols];
30+
var traversed = new ArrayList<T>();
31+
var searchQueue = new ArrayDeque<Vertex>();
32+
33+
searchQueue.add(new Vertex(rootRow, rootCol));
34+
while (!searchQueue.isEmpty()) {
35+
var vertex = searchQueue.removeFirst();
36+
int row = vertex.row;
37+
int col = vertex.col;
38+
39+
if (!explored[row][col] && graph[row][col] != null) {
40+
explored[row][col] = true;
41+
traversed.add(graph[row][col]);
42+
43+
for (int i = 0; i < 4; i++) {
44+
int nextRow = row + ROW_DIRECTIONS[i];
45+
int nextCol = col + COL_DIRECTIONS[i];
46+
47+
if (nextRow >= 0 && nextRow < rows && nextCol >= 0 && nextCol < cols) {
48+
searchQueue.add(new Vertex(nextRow, nextCol));
49+
}
50+
}
51+
}
52+
}
53+
return traversed;
54+
}
55+
56+
private static <T> boolean isGraphValid(T[][] graph, int rootRow, int rootCol) {
57+
// check if graph is not empty.
58+
if (graph.length == 0 || graph[0].length == 0) return false;
59+
60+
int rows = graph.length;
61+
int cols = graph[0].length;
62+
63+
// check if root vertex is valid.
64+
if (rootRow < 0 || rootRow >= rows || rootCol < 0 || rootCol >= cols) return false;
65+
66+
// check if graph dimensions are valid.
67+
for (var row : graph)
68+
if (row.length != cols) return false;
69+
70+
return true;
71+
}
72+
73+
74+
public static void main(String[] args) {
75+
Integer[][] graph = {
76+
{3, 2, 1},
77+
{1, 4, 4},
78+
{9, 3, null}
79+
};
80+
81+
System.out.println(
82+
bfs(graph, 0, 0)
83+
);
84+
}
85+
}

src/java/sequential/graph/dfs/RecursiveDepthFirstTraversal.java

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,24 @@
77
import java.util.Set;
88

99

10-
class RecursiveDepthFirstTraversal<T> {
10+
class RecursiveDepthFirstTraversal {
1111

12-
private Map<T, List<T>> graph;
13-
private Set<T> explored;
1412

15-
public synchronized Collection<T> dfs(Map<T, List<T>> graph, T root) {
16-
this.graph = graph;
17-
explored = new LinkedHashSet<>();
13+
public static <T> Collection<T> dfs(Map<T, List<T>> graph, T root) {
14+
var explored = new LinkedHashSet<T>();
1815

19-
var traversed = explore(root);
16+
explore(root, graph, explored);
2017

21-
clear();
22-
return traversed;
18+
return explored;
2319
}
2420

25-
private Collection<T> explore(T node) {
21+
private static <T> void explore(T node, Map<T, List<T>> graph, Set<T> explored) {
2622
explored.add(node);
2723

2824
var successors = graph.getOrDefault(node, List.of());
29-
for (var succ : successors)
30-
if (!explored.contains(succ)) explore(succ);
31-
32-
return explored;
33-
}
34-
35-
private void clear() {
36-
explored = null;
37-
graph = null;
25+
for (var succ : successors) {
26+
if (!explored.contains(succ)) explore(succ, graph, explored);
27+
}
3828
}
3929

4030

@@ -47,7 +37,7 @@ public static void main(String[] args) {
4737
);
4838

4939
System.out.println(
50-
new RecursiveDepthFirstTraversal().dfs(graph, "you")
40+
dfs(graph, "you")
5141
);
5242
}
5343
}

src/kotlin/sequential/graph/bfs/BUILD

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,10 @@ java_binary(
99
name = "bfs",
1010
main_class = "sequential.graph.bfs.BreadthFirstTraversalKt",
1111
runtime_deps = [":bfs_lib"],
12+
)
13+
14+
java_binary(
15+
name = "bfs_grid",
16+
main_class = "sequential.graph.bfs.grid.GridBreadthFirstTraversalKt",
17+
runtime_deps = [":bfs_lib"],
1218
)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package sequential.graph.bfs.grid
2+
3+
import java.util.*
4+
5+
6+
private typealias Graph<T> = Array<Array<out T>>
7+
8+
private typealias Queue = ArrayDeque<Pair<Int, Int>>
9+
10+
11+
// Grid traversal directions represented as (row, col): left, up, right, down.
12+
private val DIRECTIONS = arrayOf(0 to -1, -1 to 0, 0 to 1, 1 to 0)
13+
14+
15+
fun <T> Graph<T>.bfs(rootRow: Int, rootCol: Int): Collection<T> {
16+
val graph = this
17+
require(graph.isValid(rootRow, rootCol)) { "Invalid graph." }
18+
19+
val rows = graph.size
20+
val cols = graph[0].size
21+
val rowBounds = 0 until rows
22+
val colBounds = 0 until cols
23+
24+
val explored = Array(rows) { BooleanArray(cols) { false } }
25+
val traversed = mutableListOf<T>()
26+
val searchQueue = Queue()
27+
28+
searchQueue += rootRow to rootCol
29+
while (searchQueue.isNotEmpty()) {
30+
val (row, col) = searchQueue.removeFirst()
31+
32+
if (!explored[row][col] && graph[row][col] != null) {
33+
explored[row][col] = true
34+
traversed += graph[row][col]
35+
36+
for ((stepRow, stepCol) in DIRECTIONS) {
37+
val nextRow = row + stepRow
38+
val nextCol = col + stepCol
39+
40+
if (nextRow in rowBounds && nextCol in colBounds)
41+
searchQueue += nextRow to nextCol
42+
}
43+
}
44+
}
45+
46+
return traversed
47+
}
48+
49+
50+
private fun <T> Graph<T>.isValid(rootRow: Int, rootCol: Int): Boolean {
51+
val graph = this
52+
53+
// check if graph is not empty.
54+
if (graph.isEmpty() || graph[0].isEmpty()) return false
55+
// check if root vertex is valid.
56+
if (graph.getOrNull(rootRow)?.getOrNull(rootCol) == null) return false
57+
58+
val cols = graph[0].size
59+
60+
// check if graph dimensions are valid.
61+
for (row in graph)
62+
if (row.size != cols) return false
63+
64+
return true
65+
}
66+
67+
68+
fun main() {
69+
70+
val graph = arrayOf(
71+
arrayOf(3, 2, 1),
72+
arrayOf(1, 4, 4),
73+
arrayOf(9, 3, null)
74+
)
75+
76+
println(
77+
graph.bfs(0, 0)
78+
)
79+
}

0 commit comments

Comments
 (0)