I am trying to implement a modified version of a tree DFS without recursion and am struggling with the borrow checker. My requirement is that I want to ensure that child nodes are treated before their parent, and I would like all this to be mutable (no problem in the immutable case).
I have a simple tree structure as below:
struct Node {
value: usize,
children: Vec<Node>,
}
A normal iterative DFS might look like this (note that we are mutating the tree as we go):
fn normal_dfs(node: &mut Node) {
let mut node_stack = vec![node];
while !node_stack.is_empty() {
let current_node = node_stack.pop().unwrap();
for child_node in &mut current_node.children {
node_stack.push(child_node);
}
current_node.value += 1;
}
}
In the function above, parent nodes will be treated before their children, and I would like the opposite. I tried to build a stack of references to all the tree nodes, which I then plan to iterate backwards, ensuring that child nodes are treated before their parent:
fn modified_dfs(node: &mut Node) {
//requirement: child nodes should be treated before parent nodes
let mut node_stack = vec![node];
let mut stack_index = 0usize;
let mut stack_size = node_stack.len(); //not great but helps with borrow checker
while stack_index < stack_size {
let current_node = node_stack.get_mut(stack_index).unwrap();
for child_node in &mut current_node.children {
node_stack.push(child_node);
}
stack_size = node_stack.len();
stack_index += 1;
}
//iterate stack in reverse to make sure child nodes are treated before parents
for current_node in node_stack.iter_mut().rev() {
current_node.value += 1;
}
}
This doesn't compile with the error:
error[E0499]: cannot borrow `node_stack` as mutable more than once at a time
--> src/lib.rs:13:28
|
13 | let current_node = node_stack.get_mut(stack_index).unwrap();
| ^^^^^^^^^^ `node_stack` was mutably borrowed here in the previous iteration of the loop
error[E0499]: cannot borrow `node_stack` as mutable more than once at a time
--> src/lib.rs:15:13
|
13 | let current_node = node_stack.get_mut(stack_index).unwrap();
| ---------- first mutable borrow occurs here
14 | for child_node in &mut current_node.children {
| -------------------------- first borrow later used here
15 | node_stack.push(child_node);
| ^^^^^^^^^^ second mutable borrow occurs here
error[E0502]: cannot borrow `node_stack` as immutable because it is also borrowed as mutable
--> src/lib.rs:18:22
|
13 | let current_node = node_stack.get_mut(stack_index).unwrap();
| ---------- mutable borrow occurs here
...
18 | stack_size = node_stack.len();
| ^^^^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
error[E0499]: cannot borrow `node_stack` as mutable more than once at a time
--> src/lib.rs:23:25
|
13 | let current_node = node_stack.get_mut(stack_index).unwrap();
| ---------- first mutable borrow occurs here
...
23 | for current_node in node_stack.iter_mut().rev() {
| ^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
I think I understand the reason for the error: I have borrowed the node_stack
in an iteration, and the borrow is not "released" at the end of the iteration because child nodes have been put on the stack (it compiles if you don't push the child nodes).
What is an iterative algorithm to do this?