gpt4 book ai didi

tree - 有没有办法遍历可变树以获得随机节点?

转载 作者:行者123 更新时间:2023-11-29 08:08:36 25 4
gpt4 key购买 nike

我正在尝试更新树结构的节点。随机选择要更新的节点。要使用 Reservoir Sampling 算法对树中的节点进行采样,我必须遍历节点,因此我尝试制作一个 Iterator对于我的 Node枚举。

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

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

这是我的代码。

#![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);

}

最佳答案

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

假设我们有这个树结构:

         +-+
+----+ +----+
| +-+ |
| |
| |
+--v-+ +--v--+
| 50 | | 100 |
+----+ +-----+

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

let mut all_nodes: Vec<&mut Node> = tree.iter_mut().collect();

假设父节点在索引 0 中结束,左节点在索引 1 中,右节点在索引 2 中。

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 是彼此的可变别名。我们在完全安全的代码中违反了基本的 Rust 要求。这就是为什么这样的迭代器是不可能的。


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

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),
}
}
}
}

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

{
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;
}

关于tree - 有没有办法遍历可变树以获得随机节点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49057270/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com