【问题标题】:Recursive search of node in tree树中节点的递归搜索
【发布时间】:2016-12-02 19:56:25
【问题描述】:

我想使用两个结构构建一棵树:NodeTree,然后递归地从树中搜索目标节点。如果找到目标,则返回true,否则返回false

我面临的挑战是如何递归调用find 函数,因为它只定义在Tree 而不是Node

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

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

impl<T: Ord> Tree<T> {
    /// Creates an empty tree
    pub fn new() -> Self {
        Tree { root: None }
    }

    // search the tree
    pub fn find(&self, key: &T) -> bool {
        let root_node = &self.root; // root is Option

        match *root_node {
            Some(ref node) => {

                if node.value == *key {
                    return true;
                }

                let target_node = if *key < node.value {
                    &node.left
                } else {
                    &node.right
                };

                match *target_node {
                    Some(sub_node) => sub_node.find(key),
                    None => {
                        return false;
                    } 
                }
            }
            None => return false,
        }
    }
}

fn main() {
    let mut mytree: Tree<i32> = Tree::new();

    let node1 = Node {
        value: 100,
        left: None,
        right: None,
    };
    let boxed_node1 = Some(Box::new(node1));

    let root = Node {
        value: 200,
        left: boxed_node1,
        right: None,
    };
    let boxed_root = Some(Box::new(root));
    let mytree = Tree { root: boxed_root };

    let res = mytree.find(&100);
}

当前代码报错:

error: no method named `find` found for type `Box<Node<T>>` in the current scope
  --> src/main.rs:36:48
   |
36 |                     Some(sub_node) => sub_node.find(key),
   |                                                ^^^^
   |
   = note: the method `find` exists but the following trait bounds were not satisfied: `Node<T> : std::iter::Iterator`
   = help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `find`, perhaps you need to implement one of them:
   = help: candidate #1: `std::iter::Iterator`
   = help: candidate #2: `core::str::StrExt`

我了解find 只在Tree 上实现,所以有错误,但我认为在TreeNode 上都实现find 效率不高。有什么提示可以解决这个问题吗?

【问题讨论】:

    标签: recursion rust


    【解决方案1】:

    您需要将大部分实现移动到Node 类型,然后在Tree 中只留下一个小垫片:

    impl<T: Ord> Tree<T> {
        pub fn find(&self, key: &T) -> bool {
            self.root.as_ref().map(|n| n.find(key)).unwrap_or(false)
        }
    }
    
    impl<T: Ord> Node<T> {
        // search the tree
        pub fn find(&self, key: &T) -> bool {
            if self.value == *key {
                return true;
            }
    
            let target_node = if *key < self.value {
                &self.left
            } else {
                &self.right
            };
    
            target_node.as_ref().map(|n| n.find(key)).unwrap_or(false)
        }
    }
    

    但是,我可以通过只匹配结果来避免多重比较:

    pub fn find(&self, key: &T) -> bool {
        use ::std::cmp::Ordering::*;
    
        match self.value.cmp(key) {
            Equal => true,
            Less => self.left.as_ref().map(|n| n.find(key)).unwrap_or(false),
            Greater => self.right.as_ref().map(|n| n.find(key)).unwrap_or(false),
        }
    }
    

    或者

    pub fn find(&self, key: &T) -> bool {
        use ::std::cmp::Ordering::*;
    
        let child = match self.value.cmp(key) {
            Equal => return true,
            Less => self.left.as_ref(),
            Greater => self.right.as_ref(),
        };
    
        child.map(|n| n.find(key)).unwrap_or(false)
    }
    

    我发现target_node.as_ref().map(|n| n.find(key)).unwrap_or(false) 很难理解。我刚开始学习迭代器。是否可以一步一步解释长表达式?

    只需遵循每个函数的类型签名:

    1. self&amp;Node&lt;T&gt;
    2. &amp;self.left / &amp;self.right / target_node&amp;Option&lt;Box&lt;Node&lt;T&gt;&gt;&gt;
    3. Option::as_ref&amp;Option&lt;T&gt; 转换为 Option&lt;&amp;T&gt;。现在我们有Option&lt;&amp;Box&lt;Node&lt;T&gt;&gt;&gt;
    4. Option::map 如果选项是 Some,则将函数(可能会更改包含的类型)应用于选项,否则将其保留为 None
      1. 我们应用的函数是Node::find,它接受&amp;Node&lt;T&gt;并返回bool
      2. Box&lt;T&gt; 实现了Deref,所以T 上的任何方法都会出现在Box&lt;T&gt; 上。
      3. Automatic dereferencing 允许我们将&amp;Box&lt;T&gt; 视为Box&lt;T&gt;
      4. 现在我们有Option&lt;bool&gt;
    5. Option::unwrap_or 如果有则返回包含的值,否则返回提供的后备值。最后一个类型是bool

    没有使用 Iterator 特征。 IteratorOption 都有一个 map 方法。如果您对他们有相同的名字并做类似的事情感兴趣,那[人们称之为monad。理解 monad 很有趣,但实际使用它们并不是必需的

    【讨论】:

    • 例如,target_node.as_ref() 将引用(&Tree)转换为?? (&T)
    • 我删除了我的第一个评论问题,因为我对问太多感到难过......没想到你仍然看到它并回答了所有问题。谢谢!
    【解决方案2】:

    Node 上实现find 方法并为Tree 创建一个存根find 方法,如下所示:

    impl<T: Ord> Tree<T> {
        pub fn find(&self, key: &T) -> bool {
            match self.root.as_ref() {
                None => false,
                Some(x) => x.find(key)
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-26
      • 2012-01-26
      • 1970-01-01
      • 1970-01-01
      • 2017-06-22
      • 2014-05-10
      • 2013-03-10
      • 2018-03-19
      • 1970-01-01
      相关资源
      最近更新 更多