Skip to content

Commit 7121ffd

Browse files
Graph Traversal via DFS and BFS
1 parent b72dfb3 commit 7121ffd

File tree

3 files changed

+150
-0
lines changed

3 files changed

+150
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package algorithms.graph
2+
3+
import datastructures.graph.Graph
4+
import datastructures.basic.Queue
5+
6+
/// Breadth-First Search (BFS)
7+
/// Traverses the graph level by level from a given start node
8+
/// Uses a queue-based approach
9+
10+
/// Runs in O(V + E) time complexity
11+
12+
def BFS[T](graph: Graph[T], start: T): List[T] = {
13+
val visited = scala.collection.mutable.Set[T]()
14+
val queue = new Queue[T]()
15+
val result = scala.collection.mutable.ListBuffer[T]()
16+
17+
queue.enqueue(start)
18+
visited.add(start)
19+
20+
while (!queue.isEmpty) {
21+
val node = queue.dequeue().get
22+
result.append(node)
23+
24+
for ((neighbor, _) <- graph.getNeighbors(node)) {
25+
if (!visited.contains(neighbor)) {
26+
visited.add(neighbor)
27+
queue.enqueue(neighbor)
28+
}
29+
}
30+
}
31+
32+
result.toList
33+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package algorithms.graph
2+
3+
import datastructures.graph.Graph
4+
import datastructures.basic.Stack
5+
6+
/// Depth-First Search (DFS)
7+
/// Explores as deep as possible before backtracking
8+
/// Uses a stack-based approach
9+
10+
/// Runs in O(V + E) time complexity
11+
12+
def DFS[T](graph: Graph[T], start: T): List[T] = {
13+
val visited = scala.collection.mutable.Set[T]()
14+
val stack = new Stack[T]()
15+
val result = scala.collection.mutable.ListBuffer[T]()
16+
17+
stack.push(start)
18+
19+
while (!stack.isEmpty) {
20+
val node = stack.pop().get
21+
22+
if (!visited.contains(node)) {
23+
visited.add(node)
24+
result.append(node)
25+
26+
for ((neighbor, _) <- graph.getNeighbors(node).toList.reverse) {
27+
if (!visited.contains(neighbor)) {
28+
stack.push(neighbor)
29+
}
30+
}
31+
}
32+
}
33+
34+
result.toList
35+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package algorithms.graph
2+
3+
import datastructures.graph._
4+
import algorithms.graph.BFS
5+
import algorithms.graph.DFS
6+
import munit.FunSuite
7+
8+
class GraphTraversalTest extends FunSuite {
9+
10+
test("BFS should return correct level-order traversal") {
11+
val graph = new Graph[Char](false) // Undirected Graph
12+
graph.addEdge('A', 'B')
13+
graph.addEdge('A', 'C')
14+
graph.addEdge('B', 'D')
15+
graph.addEdge('C', 'E')
16+
17+
val result = BFS(graph, 'A')
18+
val expected = List('A', 'B', 'C', 'D', 'E')
19+
20+
assertEquals(result, expected)
21+
}
22+
23+
test("DFS should return correct depth-first traversal") {
24+
val graph = new Graph[Char](false) // Undirected Graph
25+
graph.addEdge('A', 'B')
26+
graph.addEdge('A', 'C')
27+
graph.addEdge('B', 'D')
28+
graph.addEdge('C', 'E')
29+
30+
val result = DFS(graph, 'A')
31+
32+
// Possible valid DFS orders:
33+
val expected1 = List('A', 'C', 'E', 'B', 'D')
34+
val expected2 = List('A', 'B', 'D', 'C', 'E')
35+
36+
assert(expected1 == result || expected2 == result)
37+
}
38+
39+
test("BFS should return a single node if no edges exist") {
40+
val graph = new Graph[Int](false)
41+
graph.addVertex(1)
42+
43+
val result = BFS(graph, 1)
44+
assertEquals(result, List(1))
45+
}
46+
47+
test("DFS should return a single node if no edges exist") {
48+
val graph = new Graph[Int](false)
49+
graph.addVertex(1)
50+
51+
val result = DFS(graph, 1)
52+
assertEquals(result, List(1))
53+
}
54+
55+
test("BFS should correctly traverse a directed graph") {
56+
val graph = new Graph[Char](true) // Directed Graph
57+
graph.addEdge('A', 'B')
58+
graph.addEdge('A', 'C')
59+
graph.addEdge('B', 'D')
60+
graph.addEdge('C', 'E')
61+
62+
val result = BFS(graph, 'A')
63+
val expected = List('A', 'B', 'C', 'D', 'E')
64+
65+
assertEquals(result, expected)
66+
}
67+
68+
test("DFS should correctly traverse a directed graph") {
69+
val graph = new Graph[Char](true) // Directed Graph
70+
graph.addEdge('A', 'B')
71+
graph.addEdge('A', 'C')
72+
graph.addEdge('B', 'D')
73+
graph.addEdge('C', 'E')
74+
75+
val result = DFS(graph, 'A')
76+
77+
val expected1 = List('A', 'C', 'E', 'B', 'D')
78+
val expected2 = List('A', 'B', 'D', 'C', 'E')
79+
80+
assert(expected1 == result || expected2 == result)
81+
}
82+
}

0 commit comments

Comments
 (0)