|
| 1 | +use std::fmt::Debug; |
| 2 | + |
| 3 | +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] |
| 4 | +pub struct Tree<T: Debug + Ord> { |
| 5 | + label: T, |
| 6 | + children: Vec<Box<Tree<T>>>, |
| 7 | +} |
| 8 | + |
| 9 | +impl<T: Debug + Ord> Tree<T> { |
| 10 | + pub fn new(label: T) -> Self { |
| 11 | + Self { |
| 12 | + label, |
| 13 | + children: Default::default(), |
| 14 | + } |
| 15 | + } |
| 16 | + |
| 17 | + pub fn with_child(mut self, child: Self) -> Self { |
| 18 | + self.children.insert( |
| 19 | + self.children |
| 20 | + .binary_search_by(|c| c.label.cmp(&child.label)) |
| 21 | + .unwrap_err(), |
| 22 | + Box::new(child), |
| 23 | + ); |
| 24 | + self |
| 25 | + } |
| 26 | + |
| 27 | + pub fn pov_from(&mut self, from: &T) -> bool { |
| 28 | + self.pov_from_rec(from).is_some() |
| 29 | + } |
| 30 | + |
| 31 | + fn pov_from_rec(&mut self, from: &T) -> Option<Vec<usize>> { |
| 32 | + if &self.label == from { |
| 33 | + return Some(Vec::new()); |
| 34 | + } |
| 35 | + |
| 36 | + // Run `pov_from_rec` over all children, until finding the one where it |
| 37 | + // worked. That also returns the list of indexes to traverse to find the |
| 38 | + // insertion point for the old POV. |
| 39 | + let (pos, mut index_list) = self |
| 40 | + .children |
| 41 | + .iter_mut() |
| 42 | + .enumerate() |
| 43 | + .find_map(|(i, child)| child.pov_from_rec(from).map(|index_list| (i, index_list)))?; |
| 44 | + |
| 45 | + // swap old and new POV |
| 46 | + let mut old_pov = self.children.remove(pos); |
| 47 | + std::mem::swap(self, &mut old_pov); |
| 48 | + |
| 49 | + // find parent of old POV |
| 50 | + let mut parent_of_old_pov = self; |
| 51 | + for i in index_list.iter().rev() { |
| 52 | + parent_of_old_pov = &mut parent_of_old_pov.children[*i]; |
| 53 | + } |
| 54 | + |
| 55 | + // put old POV into its new place |
| 56 | + let new_idx = parent_of_old_pov |
| 57 | + .children |
| 58 | + .binary_search_by(|c| c.label.cmp(&old_pov.label)) |
| 59 | + .unwrap_err(); |
| 60 | + parent_of_old_pov.children.insert(new_idx, old_pov); |
| 61 | + |
| 62 | + // Record index of old POV such that other recursive calls can insert |
| 63 | + // their old POV as the child of ours. |
| 64 | + index_list.push(new_idx); |
| 65 | + |
| 66 | + Some(index_list) |
| 67 | + } |
| 68 | + |
| 69 | + pub fn path_between<'a>(&'a mut self, from: &'a T, to: &'a T) -> Option<Vec<&'a T>> { |
| 70 | + if !self.pov_from(to) { |
| 71 | + return None; |
| 72 | + } |
| 73 | + self.path_from(from) |
| 74 | + } |
| 75 | + |
| 76 | + fn path_from<'a>(&'a self, from: &'a T) -> Option<Vec<&'a T>> { |
| 77 | + if &self.label == from { |
| 78 | + return Some(vec![from]); |
| 79 | + } |
| 80 | + let mut path = self.children.iter().find_map(|c| c.path_from(from))?; |
| 81 | + path.push(&self.label); |
| 82 | + Some(path) |
| 83 | + } |
| 84 | +} |
0 commit comments