algorithms_edu/algo/graph/dfs.rs
1pub mod iterative {
2 //! An implementation of iterative DFS with an adjacency list
3 //!
4 //! - Time Complexity: O(V + E)
5 //!
6 //! # Resources
7 //!
8 //! - [W. Fiset's video](https://www.youtube.com/watch?v=7fujbpJ0LB4&list=PLDV1Zeh2NRsDGO4--qE8yH72HFL1Km93P&index=4)
9
10 use crate::algo::graph::{Edge, WeightedAdjacencyList};
11
12 impl WeightedAdjacencyList {
13 /// Perform a depth first search on a graph with n nodes
14 /// from a starting point to count the number of nodes
15 /// in a given component.
16 ///
17 /// In this particular implementation we just increment a counter each time we
18 /// visit a new node. This, by itself, is not of much use, but you'll soon see that
19 /// many other advanced algorithms are based on this DFS prototype.
20 pub fn dfs(&self, start: usize) -> usize {
21 let mut count = 0;
22 let mut visited = vec![false; self.node_count()];
23 let mut stack = Vec::new();
24
25 // start by visiting the start node
26 stack.push(start);
27 visited[start] = true;
28
29 while let Some(node) = stack.pop() {
30 count += 1;
31 let neighbours = &self[node];
32 for &Edge { to, weight: _ } in neighbours {
33 if !visited[to] {
34 stack.push(to);
35 visited[to] = true;
36 }
37 }
38 }
39
40 count
41 }
42 }
43
44 #[cfg(test)]
45 mod tests {
46 use super::*;
47 #[test]
48 fn test_dfs_iterative() {
49 // Create a fully connected graph
50 // (0)
51 // / \
52 // 5 / \ 4
53 // / \
54 // 10 < -2 >
55 // +->(2)<------(1) (4)
56 // +--- \ /
57 // \ /
58 // 1 \ / 6
59 // > <
60 // (3)
61 let graph = WeightedAdjacencyList::new_directed(
62 5,
63 &[
64 (0, 1, 4.),
65 (0, 2, 5.),
66 (1, 2, -2.),
67 (1, 3, 6.),
68 (2, 3, 1.),
69 (2, 2, 10.), // Self loop
70 ],
71 );
72
73 let count = graph.dfs(0);
74 assert_eq!(count, 4);
75 println!("DFS node count starting at node 0: {}", count);
76
77 let count = graph.dfs(4);
78 assert_eq!(count, 1);
79 println!("DFS node count starting at node 4: {}", count);
80 }
81 }
82}
83pub mod recursive {
84 //! An implementation of recursive DFS with an adjacency list
85 //!
86 //! - Time Complexity: O(V + E)
87 //!
88 //! # Resources
89 //!
90 //! - [W. Fiset's video](https://www.youtube.com/watch?v=7fujbpJ0LB4&list=PLDV1Zeh2NRsDGO4--qE8yH72HFL1Km93P&index=4)
91
92 use crate::algo::graph::UnweightedAdjacencyList;
93
94 impl UnweightedAdjacencyList {
95 pub fn dfs_recursive(&self, start: usize) -> usize {
96 fn _dfs(
97 graph: &UnweightedAdjacencyList,
98 node: usize,
99 visited: &mut [bool],
100 count: &mut usize,
101 ) {
102 *count += 1;
103 visited[node] = true;
104 for &neighbour in &graph[node] {
105 if !visited[neighbour] {
106 _dfs(graph, neighbour, visited, count);
107 }
108 }
109 }
110 let mut count = 0;
111 // let visited = vec![false; self.len()];
112 _dfs(self, start, &mut vec![false; self.node_count()], &mut count);
113 count
114 }
115 }
116
117 #[cfg(test)]
118 mod tests {
119 use super::*;
120 #[test]
121 fn test_dfs_recursive() {
122 // Create a fully connected graph
123 // (0)
124 // / \
125 // / \
126 // / \
127 // < >
128 // +->(2)<------(1) (4)
129 // +--- \ /
130 // \ /
131 // \ /
132 // > <
133 // (3)
134 const N: usize = 5;
135 let mut graph = UnweightedAdjacencyList::with_size(N);
136 graph.add_directed_edge(0, 1);
137 graph.add_directed_edge(0, 2);
138 graph.add_directed_edge(1, 2);
139 graph.add_directed_edge(1, 3);
140 graph.add_directed_edge(2, 3);
141 graph.add_directed_edge(2, 2); // Self loop
142
143 let count = graph.dfs_recursive(0);
144 assert_eq!(count, 4);
145 println!("DFS node count starting at node 0: {}", count);
146
147 let count = graph.dfs_recursive(4);
148 assert_eq!(count, 1);
149 println!("DFS node count starting at node 4: {}", count);
150 }
151 }
152}