@@ -11,15 +11,15 @@ pub trait DetectCycle {
11
11
fn undirected_graph_detect_cycle_dfs < ' a > (
12
12
graph : & ' a UndirectedGraph ,
13
13
visited_node : & mut HashSet < & ' a String > ,
14
- parent : & ' a String ,
14
+ parent : Option < & ' a String > ,
15
15
u : & ' a String ,
16
16
) -> bool {
17
17
visited_node. insert ( u) ;
18
18
for ( v, _) in graph. adjacency_table ( ) . get ( u) . unwrap ( ) {
19
- if v == parent {
19
+ if matches ! ( parent , Some ( parent ) if v == parent) {
20
20
continue ;
21
21
}
22
- if visited_node. contains ( v) || undirected_graph_detect_cycle_dfs ( graph, visited_node, u , v)
22
+ if visited_node. contains ( v) || undirected_graph_detect_cycle_dfs ( graph, visited_node, Some ( u ) , v)
23
23
{
24
24
return true ;
25
25
}
@@ -36,19 +36,19 @@ fn undirected_graph_detect_cycle_bfs<'a>(
36
36
visited_node. insert ( u) ;
37
37
38
38
// Initialize the queue for BFS, storing (current node, parent node) tuples
39
- let mut queue = VecDeque :: < ( & String , & String ) > :: new ( ) ;
40
- queue. push_back ( ( u, u ) ) ;
39
+ let mut queue = VecDeque :: < ( & String , Option < & String > ) > :: new ( ) ;
40
+ queue. push_back ( ( u, None ) ) ;
41
41
42
42
while let Some ( ( u, parent) ) = queue. pop_front ( ) {
43
43
for ( v, _) in graph. adjacency_table ( ) . get ( u) . unwrap ( ) {
44
- if v == parent {
44
+ if matches ! ( parent , Some ( parent ) if v == parent) {
45
45
continue ;
46
46
}
47
47
if visited_node. contains ( v) {
48
48
return true ;
49
49
}
50
50
visited_node. insert ( v) ;
51
- queue. push_back ( ( v, u ) ) ;
51
+ queue. push_back ( ( v, Some ( u ) ) ) ;
52
52
}
53
53
}
54
54
false
@@ -60,7 +60,7 @@ impl DetectCycle for UndirectedGraph {
60
60
let adj = self . adjacency_table ( ) ;
61
61
for u in adj. keys ( ) {
62
62
if !visited_node. contains ( u)
63
- && undirected_graph_detect_cycle_dfs ( self , & mut visited_node, u , u)
63
+ && undirected_graph_detect_cycle_dfs ( self , & mut visited_node, None , u)
64
64
{
65
65
return true ;
66
66
}
@@ -167,55 +167,127 @@ impl DetectCycle for DirectedGraph {
167
167
#[ cfg( test) ]
168
168
mod test {
169
169
use crate :: data_structures:: { graph:: Graph , DirectedGraph , UndirectedGraph } ;
170
-
171
170
use super :: DetectCycle ;
172
-
173
- #[ test]
174
- fn test_detect_cycle_in_undirected_graph ( ) {
175
- let mut graph_with_cycle = UndirectedGraph :: new ( ) ;
176
-
177
- graph_with_cycle. add_edge ( ( "a" , "b" , 1 ) ) ;
178
- graph_with_cycle. add_edge ( ( "a" , "c" , 1 ) ) ;
179
- graph_with_cycle. add_edge ( ( "b" , "c" , 1 ) ) ;
180
- graph_with_cycle. add_edge ( ( "b" , "d" , 1 ) ) ;
181
- graph_with_cycle. add_edge ( ( "c" , "d" , 1 ) ) ;
182
-
183
- assert ! ( graph_with_cycle. detect_cycle_dfs( ) ) ;
184
- assert ! ( graph_with_cycle. detect_cycle_bfs( ) ) ;
185
-
186
- let mut graph_without_cycle = UndirectedGraph :: new ( ) ;
187
-
188
- graph_without_cycle. add_edge ( ( "a" , "b" , 1 ) ) ;
189
- graph_without_cycle. add_edge ( ( "a" , "c" , 1 ) ) ;
190
- graph_without_cycle. add_edge ( ( "b" , "d" , 1 ) ) ;
191
- graph_without_cycle. add_edge ( ( "c" , "e" , 1 ) ) ;
192
-
193
- assert ! ( !graph_without_cycle. detect_cycle_dfs( ) ) ;
194
- assert ! ( !graph_without_cycle. detect_cycle_bfs( ) ) ;
171
+ fn get_undirected_single_node_with_loop ( ) -> UndirectedGraph {
172
+ let mut res = UndirectedGraph :: new ( ) ;
173
+ res. add_edge ( ( "a" , "a" , 1 ) ) ;
174
+ res
195
175
}
196
-
197
- #[ test]
198
- fn test_detect_cycle_in_directed_graph ( ) {
199
- let mut graph_with_cycle = DirectedGraph :: new ( ) ;
200
-
201
- graph_with_cycle. add_edge ( ( "b" , "a" , 1 ) ) ;
202
- graph_with_cycle. add_edge ( ( "c" , "a" , 1 ) ) ;
203
- graph_with_cycle. add_edge ( ( "b" , "c" , 1 ) ) ;
204
- graph_with_cycle. add_edge ( ( "c" , "d" , 1 ) ) ;
205
- graph_with_cycle. add_edge ( ( "d" , "b" , 1 ) ) ;
206
-
207
- assert ! ( graph_with_cycle. detect_cycle_dfs( ) ) ;
208
- assert ! ( graph_with_cycle. detect_cycle_bfs( ) ) ;
209
-
210
- let mut graph_without_cycle = DirectedGraph :: new ( ) ;
211
-
212
- graph_without_cycle. add_edge ( ( "b" , "a" , 1 ) ) ;
213
- graph_without_cycle. add_edge ( ( "c" , "a" , 1 ) ) ;
214
- graph_without_cycle. add_edge ( ( "b" , "c" , 1 ) ) ;
215
- graph_without_cycle. add_edge ( ( "c" , "d" , 1 ) ) ;
216
- graph_without_cycle. add_edge ( ( "b" , "d" , 1 ) ) ;
217
-
218
- assert ! ( !graph_without_cycle. detect_cycle_dfs( ) ) ;
219
- assert ! ( !graph_without_cycle. detect_cycle_bfs( ) ) ;
176
+ fn get_directed_single_node_with_loop ( ) -> DirectedGraph {
177
+ let mut res = DirectedGraph :: new ( ) ;
178
+ res. add_edge ( ( "a" , "a" , 1 ) ) ;
179
+ res
220
180
}
221
- }
181
+ fn get_undirected_two_nodes_connected ( ) -> UndirectedGraph {
182
+ let mut res = UndirectedGraph :: new ( ) ;
183
+ res. add_edge ( ( "a" , "b" , 1 ) ) ;
184
+ res
185
+ }
186
+ fn get_directed_two_nodes_connected ( ) -> DirectedGraph {
187
+ let mut res = DirectedGraph :: new ( ) ;
188
+ res. add_edge ( ( "a" , "b" , 1 ) ) ;
189
+ res. add_edge ( ( "b" , "a" , 1 ) ) ;
190
+ res
191
+ }
192
+ fn get_directed_two_nodes ( ) -> DirectedGraph {
193
+ let mut res = DirectedGraph :: new ( ) ;
194
+ res. add_edge ( ( "a" , "b" , 1 ) ) ;
195
+ res
196
+ }
197
+ fn get_undirected_triangle ( ) -> UndirectedGraph {
198
+ let mut res = UndirectedGraph :: new ( ) ;
199
+ res. add_edge ( ( "a" , "b" , 1 ) ) ;
200
+ res. add_edge ( ( "b" , "c" , 1 ) ) ;
201
+ res. add_edge ( ( "c" , "a" , 1 ) ) ;
202
+ res
203
+ }
204
+ fn get_directed_triangle ( ) -> DirectedGraph {
205
+ let mut res = DirectedGraph :: new ( ) ;
206
+ res. add_edge ( ( "a" , "b" , 1 ) ) ;
207
+ res. add_edge ( ( "b" , "c" , 1 ) ) ;
208
+ res. add_edge ( ( "c" , "a" , 1 ) ) ;
209
+ res
210
+ }
211
+ fn get_undirected_triangle_with_tail ( ) -> UndirectedGraph {
212
+ let mut res = get_undirected_triangle ( ) ;
213
+ res. add_edge ( ( "c" , "d" , 1 ) ) ;
214
+ res. add_edge ( ( "d" , "e" , 1 ) ) ;
215
+ res. add_edge ( ( "e" , "f" , 1 ) ) ;
216
+ res. add_edge ( ( "g" , "h" , 1 ) ) ;
217
+ res
218
+ }
219
+ fn get_directed_triangle_with_tail ( ) -> DirectedGraph {
220
+ let mut res = get_directed_triangle ( ) ;
221
+ res. add_edge ( ( "c" , "d" , 1 ) ) ;
222
+ res. add_edge ( ( "d" , "e" , 1 ) ) ;
223
+ res. add_edge ( ( "e" , "f" , 1 ) ) ;
224
+ res. add_edge ( ( "g" , "h" , 1 ) ) ;
225
+ res
226
+ }
227
+ fn get_undirected_graph_with_cycle ( ) -> UndirectedGraph {
228
+ let mut res = UndirectedGraph :: new ( ) ;
229
+ res. add_edge ( ( "a" , "b" , 1 ) ) ;
230
+ res. add_edge ( ( "a" , "c" , 1 ) ) ;
231
+ res. add_edge ( ( "b" , "c" , 1 ) ) ;
232
+ res. add_edge ( ( "b" , "d" , 1 ) ) ;
233
+ res. add_edge ( ( "c" , "d" , 1 ) ) ;
234
+ res
235
+ }
236
+ fn get_undirected_graph_without_cycle ( ) -> UndirectedGraph {
237
+ let mut res = UndirectedGraph :: new ( ) ;
238
+ res. add_edge ( ( "a" , "b" , 1 ) ) ;
239
+ res. add_edge ( ( "a" , "c" , 1 ) ) ;
240
+ res. add_edge ( ( "b" , "d" , 1 ) ) ;
241
+ res. add_edge ( ( "c" , "e" , 1 ) ) ;
242
+ res
243
+ }
244
+ fn get_directed_graph_with_cycle ( ) -> DirectedGraph {
245
+ let mut res = DirectedGraph :: new ( ) ;
246
+ res. add_edge ( ( "b" , "a" , 1 ) ) ;
247
+ res. add_edge ( ( "c" , "a" , 1 ) ) ;
248
+ res. add_edge ( ( "b" , "c" , 1 ) ) ;
249
+ res. add_edge ( ( "c" , "d" , 1 ) ) ;
250
+ res. add_edge ( ( "d" , "b" , 1 ) ) ;
251
+ res
252
+ }
253
+ fn get_directed_graph_without_cycle ( ) -> DirectedGraph {
254
+ let mut res = DirectedGraph :: new ( ) ;
255
+ res. add_edge ( ( "b" , "a" , 1 ) ) ;
256
+ res. add_edge ( ( "c" , "a" , 1 ) ) ;
257
+ res. add_edge ( ( "b" , "c" , 1 ) ) ;
258
+ res. add_edge ( ( "c" , "d" , 1 ) ) ;
259
+ res. add_edge ( ( "b" , "d" , 1 ) ) ;
260
+ res
261
+ }
262
+ macro_rules! test_detect_cycle {
263
+ ( $( $name: ident: $test_case: expr, ) * ) => {
264
+ $(
265
+ #[ test]
266
+ fn $name( ) {
267
+ let ( graph, has_cycle) = $test_case;
268
+ println!( "detect_cycle_dfs: {}" , graph. detect_cycle_dfs( ) ) ;
269
+ println!( "detect_cycle_bfs: {}" , graph. detect_cycle_bfs( ) ) ;
270
+ assert_eq!( graph. detect_cycle_dfs( ) , has_cycle) ;
271
+ assert_eq!( graph. detect_cycle_bfs( ) , has_cycle) ;
272
+ }
273
+ ) *
274
+ } ;
275
+ }
276
+ test_detect_cycle ! {
277
+ undirected_empty: ( UndirectedGraph :: new( ) , false ) ,
278
+ directed_empty: ( DirectedGraph :: new( ) , false ) ,
279
+ undirected_single_node_with_loop: ( get_undirected_single_node_with_loop( ) , true ) ,
280
+ directed_single_node_with_loop: ( get_directed_single_node_with_loop( ) , true ) ,
281
+ undirected_two_nodes_connected: ( get_undirected_two_nodes_connected( ) , false ) ,
282
+ directed_two_nodes_connected: ( get_directed_two_nodes_connected( ) , true ) ,
283
+ directed_two_nodes: ( get_directed_two_nodes( ) , false ) ,
284
+ undirected_triangle: ( get_undirected_triangle( ) , true ) ,
285
+ undirected_triangle_with_tail: ( get_undirected_triangle_with_tail( ) , true ) ,
286
+ directed_triangle: ( get_directed_triangle( ) , true ) ,
287
+ directed_triangle_with_tail: ( get_directed_triangle_with_tail( ) , true ) ,
288
+ undirected_graph_with_cycle: ( get_undirected_graph_with_cycle( ) , true ) ,
289
+ undirected_graph_without_cycle: ( get_undirected_graph_without_cycle( ) , false ) ,
290
+ directed_graph_with_cycle: ( get_directed_graph_with_cycle( ) , true ) ,
291
+ directed_graph_without_cycle: ( get_directed_graph_without_cycle( ) , false ) ,
292
+ }
293
+ }
0 commit comments