@@ -5,6 +5,8 @@ use std::collections::HashSet;
5
5
use std:: hash:: Hash ;
6
6
use std:: iter:: FusedIterator ;
7
7
8
+ use rustc_hash:: { FxHashMap , FxHashSet } ;
9
+
8
10
/// Compute a path using the [depth-first search
9
11
/// algorithm](https://en.wikipedia.org/wiki/Depth-first_search).
10
12
///
@@ -51,34 +53,40 @@ where
51
53
IN : IntoIterator < Item = N > ,
52
54
FS : FnMut ( & N ) -> bool ,
53
55
{
54
- let mut path = vec ! [ start] ;
55
- let mut visited = path. iter ( ) . cloned ( ) . collect ( ) ;
56
- step ( & mut path, & mut successors, & mut success, & mut visited) . then_some ( path)
56
+ let mut to_visit = vec ! [ start] ;
57
+ let mut visited = FxHashSet :: default ( ) ;
58
+ let mut parents = FxHashMap :: default ( ) ;
59
+ while let Some ( node) = to_visit. pop ( ) {
60
+ if visited. insert ( node. clone ( ) ) {
61
+ if success ( & node) {
62
+ return Some ( build_path ( node, & parents) ) ;
63
+ }
64
+ for next in successors ( & node)
65
+ . into_iter ( )
66
+ . collect :: < Vec < _ > > ( )
67
+ . into_iter ( )
68
+ . rev ( )
69
+ {
70
+ if !visited. contains ( & next) {
71
+ parents. insert ( next. clone ( ) , node. clone ( ) ) ;
72
+ to_visit. push ( next) ;
73
+ }
74
+ }
75
+ }
76
+ }
77
+ None
57
78
}
58
79
59
- fn step < N , FN , IN , FS > ( path : & mut Vec < N > , successors : & mut FN , success : & mut FS , visited : & mut HashSet < N > ) -> bool
80
+ fn build_path < N > ( mut node : N , parents : & FxHashMap < N , N > ) -> Vec < N >
60
81
where
61
82
N : Clone + Eq + Hash ,
62
- FN : FnMut ( & N ) -> IN ,
63
- IN : IntoIterator < Item = N > ,
64
- FS : FnMut ( & N ) -> bool ,
65
83
{
66
- if success ( path. last ( ) . unwrap ( ) ) {
67
- true
68
- } else {
69
- let successors_it = successors ( path. last ( ) . unwrap ( ) ) ;
70
- for n in successors_it {
71
- if !visited. contains ( & n) {
72
- visited. insert ( n. clone ( ) ) ;
73
- path. push ( n) ;
74
- if step ( path, successors, success, visited) {
75
- return true ;
76
- }
77
- path. pop ( ) ;
78
- }
79
- }
80
- false
84
+ let mut path = vec ! [ node. clone( ) ] ;
85
+ while let Some ( parent) = parents. get ( & node) . cloned ( ) {
86
+ path. push ( parent. clone ( ) ) ;
87
+ node = parent;
81
88
}
89
+ path. into_iter ( ) . rev ( ) . collect ( )
82
90
}
83
91
84
92
/// Visit all nodes that are reachable from a start node. The node will be visited
0 commit comments