@@ -5,6 +5,8 @@ use std::collections::HashSet;
55use std:: hash:: Hash ;
66use std:: iter:: FusedIterator ;
77
8+ use rustc_hash:: { FxHashMap , FxHashSet } ;
9+
810/// Compute a path using the [depth-first search
911/// algorithm](https://en.wikipedia.org/wiki/Depth-first_search).
1012///
@@ -51,34 +53,40 @@ where
5153 IN : IntoIterator < Item = N > ,
5254 FS : FnMut ( & N ) -> bool ,
5355{
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
5778}
5879
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 >
6081where
6182 N : Clone + Eq + Hash ,
62- FN : FnMut ( & N ) -> IN ,
63- IN : IntoIterator < Item = N > ,
64- FS : FnMut ( & N ) -> bool ,
6583{
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;
8188 }
89+ path. into_iter ( ) . rev ( ) . collect ( )
8290}
8391
8492/// Visit all nodes that are reachable from a start node. The node will be visited
0 commit comments