rust - 实现二叉搜索树时不能多次借用节点作为可变节点

标签 rust binary-search-tree

我试图在 Rust 中实现二叉搜索树,但在插入元素时遇到了问题。在 Rust 中执行此操作的惯用方法是什么?

这是我的实现:

use std::cmp::Ordering;

pub struct BinarySearchTree {
    root: OptNode,
    size: u32,
}

type OptNode = Option<Box<Node>>;

struct Node {
    key: i32,
    left: OptNode,
    right: OptNode,
}

impl BinarySearchTree {
    pub fn new() -> Self {
        BinarySearchTree {
            root: None,
            size: 0,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.size == 0
    }

    pub fn size(&self) -> u32 {
        self.size
    }

    pub fn contains(&self, key: i32) -> bool {
        let mut node = &self.root;
        while let Some(ref boxed_node) = *node {
            match key.cmp(&boxed_node.key) {
                Ordering::Less => node = &boxed_node.left,
                Ordering::Greater => node = &boxed_node.right,
                Ordering::Equal => return true,
            }
        }

        false
    }

    pub fn insert(&mut self, key: i32) {
        let mut node = &mut self.root;
        while let Some(ref mut boxed_node) = *node {
            match key.cmp(&boxed_node.key) {
                Ordering::Less => node = &mut boxed_node.left,
                Ordering::Greater => node = &mut boxed_node.right,
                Ordering::Equal => return,
            }
        }

        *node = Some(Box::new(Node {
            key: key,
            left: None,
            right: None,
        }));
    }
}

fn main() {}

这是我遇到的错误:

error[E0499]: cannot borrow `node.0` as mutable more than once at a time
  --> src/main.rs:47:24
   |
47 |         while let Some(ref mut boxed_node) = *node {
   |                        ^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
...
60 |     }
   |     - mutable borrow ends here

error[E0506]: cannot assign to `node` because it is borrowed
  --> src/main.rs:49:35
   |
47 |         while let Some(ref mut boxed_node) = *node {
   |                        ------------------ borrow of `node` occurs here
48 |             match key.cmp(&boxed_node.key) {
49 |                 Ordering::Less => node = &mut boxed_node.left,
   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `node` occurs here

error[E0506]: cannot assign to `node` because it is borrowed
  --> src/main.rs:50:38
   |
47 |         while let Some(ref mut boxed_node) = *node {
   |                        ------------------ borrow of `node` occurs here
...
50 |                 Ordering::Greater => node = &mut boxed_node.right,
   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `node` occurs here

error[E0506]: cannot assign to `*node` because it is borrowed
  --> src/main.rs:55:9
   |
47 |           while let Some(ref mut boxed_node) = *node {
   |                          ------------------ borrow of `*node` occurs here
...
55 | /         *node = Some(Box::new(Node {
56 | |             key: key,
57 | |             left: None,
58 | |             right: None,
59 | |         }));
   | |___________^ assignment to borrowed `*node` occurs here

最佳答案

Rust 的编译器还不够复杂(还?)来处理这种情况。 Rust 看到你试图多次可变地借用相同的值,因为它看到循环中对同一个变量重复可变借用。当然,这不是你想要做的,因为你想在每次迭代时重新分配变量,但 Rust 不支持分配给被借用的变量。

我们需要做的是拥有中间变量,以便编译器可以正确跟踪借用。我们如何创建不确定数量的变量?用递归!

impl BinarySearchTree {
    pub fn insert(&mut self, key: i32) {
        fn insert_node(node: &mut OptNode, key: i32) {
            if let Some(ref mut boxed_node) = *node {
                match key.cmp(&boxed_node.key) {
                    Ordering::Less => insert_node(&mut boxed_node.left, key),
                    Ordering::Greater => insert_node(&mut boxed_node.right, key),
                    Ordering::Equal => return,
                }
            } else {
                *node = Some(Box::new(Node { key: key, left: None, right: None}));
            }
        }

        insert_node(&mut self.root, key)
    }
}

注意:尽管此算法是尾递归的,但 Rust 不会将其优化为尾调用,因此在退化的情况下可能会导致堆栈溢出。

关于rust - 实现二叉搜索树时不能多次借用节点作为可变节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38043377/

相关文章:

rust - 可变与不可变生命周期

elasticsearch - 对于Rust Rocket框架,是否可以将GraphQL连接到elasticsearch?

c - 如何将 Rust `Args` 转换为 argc 和 argv C 等价物?

JavaScript BST 递归。如何删除引用为 "this"的节点类?

c++ - 创建一棵树

rust - 源特征不可访问

rust - Rust 中的递归问题

python - 从二叉搜索树创建列表

java - 比较器和 BST

java - 通过二叉搜索树中单词计数的降序打印单词计数器