搜索BST节点的后继者,“克隆以满足借用检查器”灾难

E100帕维尔

我正在尝试在Rust中实现BST。我的结构看起来像这样:

pub struct Node<T> {  
    key: T,  
    parent: Option<Box<Node<T>>>,  
    left: Option<Box<Node<T>>>,  
    right: Option<Box<Node<T>>>,  
}  

我正在研究一种用于查找当前节点的后继者的方法。经过与借阅检查器长时间的战斗之后,我使它工作了,但现在看起来像这样:

//If right node exists - successor is a min node in it.
//Else - go up a parent node. If parent is None, no successor.
//If origin was parent's left node - parent is a successor.
//Else - go up another level.
pub fn succ(&self) -> Option<Box<Node<T>>> {

    match self.right {
        Some(ref node) => Some(node.min()),
        None => {
            let mut origin = Box::new(self.clone()); //To match types
            let mut parent = origin.parent.clone(); //`Node<T>` not a copy type

            loop {
                let parent_node = match parent.clone() {
                    Some(node) => node,
                    None => break,
                };
                let right_of_parent = match parent_node.clone().right {
                    Some(node) => node,
                    None => break,
                };
                if *origin != *right_of_parent {
                    break;
                }

                origin = parent_node;
                parent = origin.parent.clone();
            }
            parent
        }
    }
}  

如果删除所有.clone()s,则编译器会因“部分移动的值”和“由于借入而无法分配”错误而开始哭泣。有没有一种方法可以使此代码更加惯用而又避免克隆地狱?

UPD:
希望发布最终得到的解决方案。
首先,上面的代码不起作用,因为父字段不包含引用,而是父节点的副本。因此最后,问题变成了“如何实现对父节点的引用”。
我考虑了下面的答案,一些相关的答案,最后我得出的结论是,对于一个我什至不打算在线发布的玩具项目来说,这样做是不值得的。我发现不是最有效的解决方案,但绝对是更简单的解决方案-根本不用父引用。
我从上面的结构中删除了父字段,并创建了另一个结构:

pub struct Tree<T> {
    root: Option<Box<Node<T>>>,
}

现在,我从树的根中搜索父级。我的succ函数现在看起来像这样:

fn succ<'a>(&'a self, node: &'a Node<T>) -> Option<&Node<T>> {
    match node.right {
        Some(ref rnode) => rnode.min(),
        None => {
            let mut succ = None;
            let mut root = self.root.as_ref();
            loop {
                root = match root {
                    Some(ref rootnode) => {
                        match node.key.cmp(&rootnode.key) {
                            Ordering::Less => {
                                succ = Some(&***rootnode);
                                rootnode.left.as_ref()
                            }
                            Ordering::Greater => rootnode.right.as_ref(),
                            Ordering::Equal => break,
                        }
                    }
                    None => break,
                }
            }
            succ
        }
    }
}
克里斯·爱默生

欢迎来到Rust和Stack Overflow!

这里的主要问题是Node定义:

pub struct Node<T> {  
    key: T,  
    parent: Option<Box<Node<T>>>,  
    left: Option<Box<Node<T>>>,  
    right: Option<Box<Node<T>>>,  
}

在Rust中,Box<T> 拥有值,而不是拥有别名的指针。您将无法创建任何非平凡的树。

相反Box,您可以尝试对引用进行计数Rc<T>您可以将Weak指针用于父链接,以避免使它们保持活动状态:

use std::rc::{Rc,Weak};
pub struct Node<T> {  
    key: T,  
    parent: Option<Weak<Node<T>>>,  
    left: Option<Rc<Node<T>>>,  
    right: Option<Rc<Node<T>>>,  
}

排序后,您就不再使用引用了。每次您执行以下操作:

let mut parent = origin.parent; //.clone();

凡在你的版本origin.parent是一个类型的Option<Box<Node<T>>>,你想移动Option场出来的origin-因此,为什么你不得不添加clone()(其克隆内的节点Box,不是指针!)。但是,您并不是真的想搬出;而是要搬出去。您只需要引用它,例如:

let parent = &origin.parent;

或同时进行None检查:

match origin.parent {
    Some(ref parent_ptr) => { ... },
    None => { ... }
}

我希望这有帮助!

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何证明从最小节点在BST中找到n-1次后继者是O(n)?

来自分类Dev

bst中连续k次调用树后继者

来自分类Dev

pygraphviz:使用后继者找到最大秩节点

来自分类Dev

二叉搜索树中节点的后继 - Swift

来自分类Dev

在BST中搜索节点时出现分段错误

来自分类Dev

在逻辑上拆分借用以解决启用NLL的借用检查器的限制是否安全?

来自分类Dev

Rust借用检查器在if语句中引发错误

来自分类Dev

借阅检查器“无法移出借用内容”

来自分类Dev

Neuraxle的RandomSearch()后继者

来自分类Dev

通过检查所有后继元素节点值是否都大于某个固定值来输出XML节点?

来自分类Dev

如何使用TypeScript克隆包含Angular选择器的节点?

来自分类Dev

Express 4的节点检查器

来自分类Dev

Express 4的节点检查器

来自分类Dev

删除叶子节点BST

来自分类Dev

BST节点删除

来自分类Dev

在BST中插入节点

来自分类Dev

BST中的节点计数

来自分类Dev

将节点插入BST

来自分类Dev

重启节点后如何重启节点检查器?

来自分类Dev

节点检查器无法连接到节点

来自分类Dev

节点检查器不适用于节点6.0.0

来自分类Dev

节点检查器无法连接到节点

来自分类Dev

循环中看似不一致的借用检查器行为

来自分类Dev

为什么通过提取方法进行重构会触发借用检查器错误?

来自分类Dev

BST中的范围搜索

来自分类Dev

bst分割故障搜索

来自分类Dev

BST中的范围搜索

来自分类Dev

在 BST 中搜索 double

来自分类Dev

检查一棵树是否是二叉搜索树(BST)