首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >有没有一种方法可以遍历可变树以获得随机节点?

有没有一种方法可以遍历可变树以获得随机节点?
EN

Stack Overflow用户
提问于 2018-03-02 03:26:48
回答 1查看 705关注 0票数 3

我正在尝试更新树结构的一个节点。随机选择要更新的节点。要使用库采样算法对树中的节点进行采样,我必须遍历这些节点,因此我尝试为我的Node枚举创建一个Iterator

问题是,一方面,我必须将子节点的引用存储在堆栈或队列中,但另一方面,我必须返回父节点的可变引用。Rust不允许对一个值进行多个可变引用,也不允许将不可变引用转换为可变引用。

有没有一种方法可以遍历可变树?或者,是否有另一种方法可以随机获取对树中节点的可变引用?

这是我的代码。

代码语言:javascript
复制
#![feature(box_syntax, box_patterns)]
extern crate rand;

// Simple binary tree structure
#[derive(Debug)]
enum Node {
    Leaf(u8),
    Branch(Box<Node>, Box<Node>),
}

impl Node {
    fn iter_mut(&mut self) -> IterMut {
        IterMut {
            stack: vec![self],
        }
    }

    fn pick_random_node_mut<'a>(&'a mut self) -> &'a mut Node {
        // Revervoir sampling
        let rng = &mut rand::thread_rng();
        rand::seq::sample_iter(rng, self.iter_mut(), 1)
            .ok().and_then(|mut v| v.pop()).unwrap()
    }
}

// An iterator for `Node`
struct IterMut<'a> {
    stack: Vec<&'a mut Node>,
}

impl <'a> Iterator for IterMut<'a> {
    type Item = &'a mut Node;

    fn next(&mut self) -> Option<&'a mut Node> {
        let node = self.stack.pop()?;

        // I am stucking here: cannot borrow `*node` as mutable more than once at a time
        if let &mut Node::Branch(box ref mut a, box ref mut b) = node {
            self.stack.push(b);
            self.stack.push(a);
        }
        Some(node)
    }
}

fn main() {
    use Node::*;

    let mut tree: Node = Branch(box Leaf(1), box Leaf(2));
    println!("{:?}", tree);

    {
        let node: &mut Node = tree.pick_random_node_mut();
        *node = Leaf(3);
    }
    println!("{:?}", tree);

}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-12 06:37:07

不,编写对树节点的可变引用的迭代器是不安全的。

假设我们有这样的树结构:

代码语言:javascript
复制
         +-+
    +----+ +----+
    |    +-+    |
    |           |
    |           |
 +--v-+      +--v--+
 | 50 |      | 100 |
 +----+      +-----+

如果存在这样的迭代器,我们可以这样调用它:

代码语言:javascript
复制
let mut all_nodes: Vec<&mut Node> = tree.iter_mut().collect();

假设父节点位于索引0中,左侧节点位于索引1中,右侧节点位于索引2中。

代码语言:javascript
复制
let (head, tail) = all_nodes.split_at_mut(1);

let x = match &mut head[0] {
    Branch(ref mut l, _) => l,
    Leaf(_) => unreachable!(),
};

let y = &mut tail[1];

现在,xy是彼此的可变别名。在完全安全的代码中,违反了基本的锈蚀要求。这就是为什么这样的迭代器是不可能的。

您可以实现对树中值的可变引用的迭代器:

代码语言:javascript
复制
impl<'a> Iterator for IterMut<'a> {
    type Item = &'a mut u8;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let node = self.stack.pop()?;

            match node {
                Node::Branch(a, b) => {
                    self.stack.push(b);
                    self.stack.push(a);
                }
                Node::Leaf(l) => return Some(l),
            }
        }
    }
}

这是安全的,因为无法从一个可变引用到一个值再到另一个值。然后,您可以在此基础上构建随机选择:

代码语言:javascript
复制
{
    let rando = match rand::seq::sample_iter(&mut rand::thread_rng(), tree.iter_mut(), 1) {
        Ok(mut v) => v.pop().unwrap(),
        Err(_) => panic!("Not enough elements"),
    };

    *rando += 1;
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49057270

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档