Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

rust - Is there a way to iterate over a mutable tree to get a random node?

I am trying to update a node of a tree structure. A node which is to be updated is selected randomly. To sample a node in the tree using the Reservoir Sampling algorithm, I have to iterate over the nodes, so I have tried to make an Iterator for my Node enum.

The problem is that, on the one hand, I have to store references for child nodes in a stack or queue, however on the other hand, I have to return a mutable reference for a parent node. Rust does not allow to make multiple mutable references for one value, neither to convert an immutable reference into a mutable reference.

Is there a way to iterate over a mutable tree? Or is there another approach to randomly get a mutable reference to a node in a tree?

Here is my code.

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

}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

No, it is not safe to write an iterator of the mutable references to the nodes of a tree.

Assume we have this tree structure:

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

If such an iterator existed, we could call it like this:

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

Assume that the parent node ends up in index 0, the left node in index 1, and the right node in index 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];

Now x and y are mutable aliases to each other. We have violated a fundamental Rust requirement in completely safe code. That's why such an iterator is not possible.


You could implement an iterator of mutable references to the values in the tree:

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

This is safe because there's no way to go from one mutable reference to a value to another one. You can then build your random selection on top of that:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...