【问题标题】:Can't do breadth-first search on a binary tree in Rust无法在 Rust 中对二叉树进行广度优先搜索
【发布时间】:2019-12-29 10:03:18
【问题描述】:

我已经在 Rust 中实现了一棵二叉树作为一个学习项目,但未能将其横向以广度优先搜索方式打印树。

问题是我无法重新分配搜索队列 (children),因为它是借来的,而且寿命不够长。

https://gist.github.com/varshard/3874803cd035e27facb67c59e89c3c1c#file-binary_tree-rs-L39

我该如何纠正这个问题?

use std::fmt::Display;

type Branch<'a, T> = Option<Box<Node<'a, T>>>;

struct Node<'a, T: PartialOrd + Display> {
    value: &'a T,
    left: Branch<'a, T>,
    right: Branch<'a, T>
}

impl<'a, T: PartialOrd + Display> Node<'a, T> {
    fn insert(&mut self, value: &'a T) {
        let target_node = if value > self.value { &mut self.right } else { &mut self.left };
        match target_node {
            Some(ref mut node) => node.insert(value),
            None => {
                let new_node = Node{ value: value, left: None, right: None};
                *target_node = Some(Box::new(new_node))
            }
        }
    }
    fn display(&'a self) {
        let mut children: Vec<Option<&Node<'a, T>>> = Vec::new();
        children.push(Some(self));

        while children.len() > 0 {
            for child in &children {
                match child {
                    Some(node) => {
                        print!("{} ", node.value);
                    },
                    None => {
                        print!(" ")
                    }
                }
            }
            println!("");
            // Error: children doesn't live long enough;
            children = self.to_vec(&children);
        }
    }
    fn to_vec(&self, nodes: &'a Vec<Option<&Node<'a, T>>>) -> Vec<Option<&Node<'a, T>>> {
        let mut children: Vec<Option<&Node<'a, T>>> = Vec::new();
        for node_option in nodes {
            match node_option {
                Some(node) => {
                    match &node.left {
                        Some(left) => {
                            children.push(Some(left));
                            match &node.right {
                                Some(right) => {
                                    children.push(Some(right));
                                },
                                None => {
                                    children.push(None);
                                }
                            }
                        },
                        None => {
                            children.push(None);
                            match &node.right {
                                Some(right) => {
                                    children.push(Some(right));
                                },
                                None => {
                                    children.push(None);
                                }
                            }
                        }
                    }
                },
                None => {}
            }
        }

        children
    }
}

fn main() {
    let root_val = 5;
    let mut root = Node{ value: &root_val, left: None, right: None };
    root.insert(&3);
    root.insert(&4);
    root.insert(&1);
    root.insert(&6);

    root.display();
}

【问题讨论】:

  • 这可能是有用的阅读:rust-unofficial.github.io/too-many-lists
  • to_vec 究竟应该做什么?为什么它需要Node (self) 和Nodes 的向量?
  • 它假设返回传递给它的节点的子节点向量。基本上,更深层次的节点。 Idf 我传递了根节点,然后它将返回树的第 2 层上的节点。如果我通过了 2 级的节点,那么它将返回 3 级的节点。我的错,&amp;self 不是必需的,应该删除。

标签: rust binary-tree


【解决方案1】:

this reddit comment复制我的答案:

有一种方法可以直接解决您的问题,但我认为有更好的选择可以使代码更易于编写和理解。对于直接修复,您可以进行一些终身调整。而不是

fn to_vec(&self, nodes: &'a Vec<Option<&Node<'a, T>>>) -> Vec<Option<&Node<'a, T>>> {

你需要:

fn to_vec<'b>(&self, nodes: &Vec<Option<&'b Node<'a, T>>>) -> Vec<Option<&'b Node<'a, T>>>

那里有什么不同?在第一种情况下,我们说nodes&amp;'a Vec。也就是说,Vec 的借用与树中的 value 引用一样长。这是一个很长的生命周期,这也是编译器生气的原因。

现在,如果您只是从 &amp;Vec 中删除 'a,编译器会抱怨其他问题:

   |
42 |     fn to_vec(&self, nodes: &Vec<Option<&Node<'a, T>>>) -> Vec<Option<&Node<'a, T>>> {
   |                                         ------------       -------------------------
   |                                         |
   |                                         this parameter and the return type are declared with different lifetimes...
...
76 |         children
   |         ^^^^^^^^ ...but data from `nodes` is returned here

也许这是促使您首先将'a 放在&amp;Vec 上的错误。我们需要用不同的方式来解决它。这里要理解的重要一点是,返回值不包含直接对nodes 向量的引用,但它确实包含nodes 向量内容的副本,即&amp;Node 引用。我们需要告诉编译器,尽管nodes 引用不会 存在很长时间,但它的内容确实 存在更长的时间。这就是我们在上面的修复中创建新生命周期'b 的原因。

这在客观上非常令人困惑。就个人而言,我宁愿避免解决这些棘手的问题,只是让事物保持更长的生命,而不是推理它们究竟能活多久。困难的根源在于我们正在销毁第 39 行的 children 向量。如果我们能够保留它,并且不断清空并重新填充它,Rust 会给我们带来更轻松的时间。您是否考虑过在这里使用std::collections::VecDeque 而不是Vec?你可以在你的while循环之外构造它一次,然后你可以传递&amp;mut children,而不用担心它的生命周期。我认为队列通常是广度优先遍历的首选数据结构,新的子节点添加到后面,遍历本身从前面读取。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多