Skip to content

Commit f7e1f71

Browse files
committed
DFS API now returns edges, skips root
1 parent 1c6f43a commit f7e1f71

File tree

4 files changed

+46
-40
lines changed

4 files changed

+46
-40
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Rather than try to persuade you with words, this repository aims to show by exam
6969
### [Network flows](src/graph/flow.rs)
7070

7171
- Dinic's blocking maximum flow
72+
- Minimum cut
7273
- Hopcroft-Karp bipartite matching
7374
- Minimum cost maximum flow
7475

src/graph/mod.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,18 @@ mod test {
130130

131131
#[test]
132132
fn test_adj_list() {
133-
let mut graph = Graph::new(4, 4);
134-
graph.add_edge(0, 1);
133+
let mut graph = Graph::new(5, 6);
134+
graph.add_edge(2, 3);
135+
graph.add_edge(2, 4);
136+
graph.add_edge(4, 1);
135137
graph.add_edge(1, 2);
136-
graph.add_edge(1, 3);
137-
graph.add_edge(3, 0);
138+
graph.add_undirected_edge(0, 2);
138139

139-
let adj: Vec<(usize, usize)> = graph.adj_list(1).collect();
140+
let adj = graph.adj_list(2).collect::<Vec<_>>();
140141

141-
assert_eq!(adj, vec![(2, 3), (1, 2)]);
142+
assert_eq!(adj, vec![(5, 0), (1, 4), (0, 3)]);
143+
for (e, v) in adj {
144+
assert_eq!(v, graph.endp[e]);
145+
}
142146
}
143147
}

src/graph/util.rs

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,16 @@ impl Graph {
6161
dist
6262
}
6363

64-
pub fn dfs(&self, u: usize) -> DfsIterator {
64+
pub fn dfs(&self, root: usize) -> DfsIterator {
65+
let mut visited = vec![false; self.num_v()];
66+
visited[root] = true;
6567
let adj_iters = (0..self.num_v())
6668
.map(|u| self.adj_list(u))
6769
.collect::<Vec<_>>();
6870

6971
DfsIterator {
70-
visited: vec![false; self.num_v()],
71-
stack: vec![u],
72+
visited,
73+
stack: vec![root],
7274
adj_iters,
7375
}
7476
}
@@ -81,32 +83,23 @@ pub struct DfsIterator<'a> {
8183
}
8284

8385
impl<'a> Iterator for DfsIterator<'a> {
84-
type Item = usize;
86+
type Item = (usize, usize);
8587

86-
/// Returns next vertex in the DFS
88+
/// Returns next edge and vertex in the depth-first traversal
89+
// Refs: https://www.geeksforgeeks.org/iterative-depth-first-traversal/
90+
// https://en.wikipedia.org/wiki/Depth-first_search
8791
fn next(&mut self) -> Option<Self::Item> {
88-
// Sources:
89-
// https://www.geeksforgeeks.org/iterative-depth-first-traversal/
90-
// https://en.wikipedia.org/wiki/Depth-first_search
91-
while let Some(&u) = self.stack.last() {
92-
if let Some((_, v)) = self.adj_iters[u].next() {
92+
loop {
93+
let &u = self.stack.last()?;
94+
while let Some((e, v)) = self.adj_iters[u].next() {
9395
if !self.visited[v] {
96+
self.visited[v] = true;
9497
self.stack.push(v);
98+
return Some((e, v));
9599
}
96-
} else {
97-
self.stack.pop();
98-
}
99-
100-
// Stack may contain same vertex twice. So
101-
// we return the popped item only
102-
// if it is not visited.
103-
if !self.visited[u] {
104-
self.visited[u] = true;
105-
return Some(u);
106100
}
101+
self.stack.pop();
107102
}
108-
109-
None
110103
}
111104
}
112105

@@ -153,31 +146,38 @@ mod test {
153146

154147
#[test]
155148
fn test_dfs() {
156-
let mut graph = Graph::new(4, 8);
149+
let mut graph = Graph::new(4, 6);
157150
graph.add_edge(0, 2);
158151
graph.add_edge(2, 0);
159152
graph.add_edge(1, 2);
160153
graph.add_edge(0, 1);
161154
graph.add_edge(3, 3);
162155
graph.add_edge(2, 3);
163156

164-
let dfs_search = graph.dfs(2).collect::<Vec<_>>();
165-
assert_eq!(dfs_search, vec![2, 3, 0, 1]);
157+
let dfs_root = 2;
158+
let dfs_traversal = std::iter::once(dfs_root)
159+
.chain(graph.dfs(dfs_root).map(|(_, v)| v))
160+
.collect::<Vec<_>>();
161+
162+
assert_eq!(dfs_traversal, vec![2, 3, 0, 1]);
166163
}
167164

168165
#[test]
169166
fn test_dfs2() {
170-
let mut graph = Graph::new(5, 8);
167+
let mut graph = Graph::new(5, 6);
171168
graph.add_edge(0, 2);
172169
graph.add_edge(2, 1);
173170
graph.add_edge(1, 0);
174171
graph.add_edge(0, 3);
175172
graph.add_edge(3, 4);
176173
graph.add_edge(4, 0);
177174

178-
let dfs_search = graph.dfs(0).collect::<Vec<_>>();
179-
//Note this is not the only valid DFS
180-
assert_eq!(dfs_search, vec![0, 3, 4, 2, 1]);
175+
let dfs_root = 0;
176+
let dfs_traversal = std::iter::once(dfs_root)
177+
.chain(graph.dfs(dfs_root).map(|(_, v)| v))
178+
.collect::<Vec<_>>();
179+
180+
assert_eq!(dfs_traversal, vec![0, 3, 4, 2, 1]);
181181
}
182182

183183
#[test]
@@ -190,10 +190,11 @@ mod test {
190190
}
191191
}
192192

193-
let mut dfs_search = graph.dfs(7);
194-
let mut dfs_check = vec![];
195-
for _ in 0..num_v {
196-
dfs_check.push(dfs_search.next().unwrap());
193+
let dfs_root = 7;
194+
let mut dfs_search = graph.dfs(dfs_root);
195+
let mut dfs_check = vec![dfs_root];
196+
for _ in 1..num_v {
197+
dfs_check.push(dfs_search.next().unwrap().1);
197198
assert!(dfs_search.stack.len() <= num_v + 1);
198199
}
199200

src/order.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl SparseIndex {
8080
/// It combines the offline algorithm with square root decomposition, resulting in an
8181
/// asymptotically suboptimal but simple algorithm with good amortized performance:
8282
/// N inserts interleaved with Q queries yields O(N sqrt Q + Q log N) time complexity
83-
/// in general, or O(N + Q log N) if all queries come after all inserts.
83+
/// in general, or O((N + Q) log N) if all queries come after all inserts.
8484
// Proof: the Q log N term comes from calls to slice_lower_bound(). As for the N sqrt Q,
8585
// note that between successive times when the hull is rebuilt, O(N) work is done,
8686
// and the running totals of insertions and queries satisfy del_N (del_Q + 1) > N.

0 commit comments

Comments
 (0)