Skip to content

Commit e99545d

Browse files
committed
feat(dfs): use a non-recursive version
1 parent 471a0fd commit e99545d

File tree

2 files changed

+31
-28
lines changed

2 files changed

+31
-28
lines changed

benches/algos-fill.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,7 @@ fn no_path_bfs(c: &mut Criterion) {
164164

165165
fn no_path_dfs(c: &mut Criterion) {
166166
c.bench_function("fill-no_path_dfs", |b| {
167-
b.iter(|| {
168-
assert_eq!(
169-
dfs(Pt::new(2, 3), successors, |_| false),
170-
None
171-
)
172-
});
167+
b.iter(|| assert_eq!(dfs(Pt::new(2, 3), successors, |_| false), None));
173168
});
174169
}
175170

src/directed/dfs.rs

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use std::collections::HashSet;
55
use std::hash::Hash;
66
use 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>
6081
where
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

Comments
 (0)