【问题标题】:Mutating a tree while performing a modified DFS without recursion在没有递归的情况下执行修改后的 DFS 时改变树
【发布时间】:2020-06-15 13:05:57
【问题描述】:

我正在尝试实现树 DFS 的修改版本没有递归,并且正在努力使用借用检查器。我的要求是我要确保子节点在其父节点之前被处理,并且我希望所有这些都是可变的(在不可变的情况下没有问题)。

我有一个简单的树结构如下:

struct Node {
    value: usize,
    children: Vec<Node>,
}

一个普通的迭代 DFS 可能看起来像这样(注意我们正在改变树):

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;
    }
}

在上面的函数中,父节点将在其子节点之前被处理,我希望相反。我尝试构建一个对所有树节点的引用堆栈,然后我计划向后迭代,确保子节点在其父节点之前被处理:

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;
    }
}

编译时出错:

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

我想我理解错误的原因:我在迭代中借用了node_stack,并且在迭代结束时借用没有“释放”,因为子节点已被放入堆栈(它编译如果你不推送子节点)。

执行此操作的迭代算法是什么?

【问题讨论】:

标签: rust tree depth-first-search


【解决方案1】:

如果你真的必须可变地做,你可以像这样使用RcRefCell

use std::cell::RefCell;
use std::rc::Rc;

struct Node {
    value: usize,
    children: Vec<Rc<RefCell<Node>>>,
}

fn modified_dfs(node: Rc<RefCell<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[stack_index].clone();
        for child_node in &current_node.borrow().children {
            {
                // Do something mutable with child_node
                child_node.borrow_mut();
            }
            node_stack.push(child_node.clone());
        }

        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.borrow_mut().value += 1;
    }
}

【讨论】:

    猜你喜欢
    • 2013-07-22
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 2021-04-11
    • 2016-08-13
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    相关资源
    最近更新 更多