Skip to content

Commit c21c97e

Browse files
committed
fix!(dfs): never visit the same node twice
All path combinations could be visited, thus leading to an explosion of the number of possibilities. For DFS, this makes no sense as if we encounter a state that has been previously seen, we know that there is no possible way to reach a goal through this state or it would have been encountered already. However, this adds two new bounds on the node type: `Clone` and `Hash`.
1 parent cf63a62 commit c21c97e

1 file changed

Lines changed: 8 additions & 6 deletions

File tree

src/directed/dfs.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,19 @@ use std::iter::FusedIterator;
4646
/// ```
4747
pub fn dfs<N, FN, IN, FS>(start: N, mut successors: FN, mut success: FS) -> Option<Vec<N>>
4848
where
49-
N: Eq,
49+
N: Clone + Eq + Hash,
5050
FN: FnMut(&N) -> IN,
5151
IN: IntoIterator<Item = N>,
5252
FS: FnMut(&N) -> bool,
5353
{
5454
let mut path = vec![start];
55-
step(&mut path, &mut successors, &mut success).then_some(path)
55+
let mut visited = path.iter().cloned().collect();
56+
step(&mut path, &mut successors, &mut success, &mut visited).then_some(path)
5657
}
5758

58-
fn step<N, FN, IN, FS>(path: &mut Vec<N>, successors: &mut FN, success: &mut FS) -> bool
59+
fn step<N, FN, IN, FS>(path: &mut Vec<N>, successors: &mut FN, success: &mut FS, visited: &mut HashSet<N>) -> bool
5960
where
60-
N: Eq,
61+
N: Clone + Eq + Hash,
6162
FN: FnMut(&N) -> IN,
6263
IN: IntoIterator<Item = N>,
6364
FS: FnMut(&N) -> bool,
@@ -67,9 +68,10 @@ where
6768
} else {
6869
let successors_it = successors(path.last().unwrap());
6970
for n in successors_it {
70-
if !path.contains(&n) {
71+
if !visited.contains(&n) {
72+
visited.insert(n.clone());
7173
path.push(n);
72-
if step(path, successors, success) {
74+
if step(path, successors, success, visited) {
7375
return true;
7476
}
7577
path.pop();

0 commit comments

Comments
 (0)