use super::super::types::EMPTY;
fn post_tree(root: usize, mut k: i64, child: &mut [i64], sibling: &[i64], order: &mut [i64]) -> i64 {
let mut stack = vec![root as i64];
while let Some(&i) = stack.last() {
let i = i as usize;
if child[i] != EMPTY {
let mut to_push = Vec::new();
let mut f = child[i];
while f != EMPTY {
to_push.push(f);
f = sibling[f as usize];
}
stack.extend(to_push.iter().rev());
child[i] = EMPTY;
} else {
stack.pop();
order[i] = k;
k += 1;
}
}
k
}
pub fn postorder(nn: usize, parent: &[i64], nv: &[i64], fsize: &[i64]) -> Vec<i64> {
let mut child = vec![EMPTY; nn];
let mut sibling = vec![EMPTY; nn];
for j in (0..nn).rev() {
if nv[j] > 0 {
let p = parent[j];
if p != EMPTY {
sibling[j] = child[p as usize];
child[p as usize] = j as i64;
}
}
}
for i in 0..nn {
if nv[i] > 0 && child[i] != EMPTY {
let mut fprev = EMPTY;
let mut maxfrsize = EMPTY;
let mut bigfprev = EMPTY;
let mut bigf = EMPTY;
let mut f = child[i];
while f != EMPTY {
let frsize = fsize[f as usize];
if frsize >= maxfrsize {
maxfrsize = frsize;
bigfprev = fprev;
bigf = f;
}
fprev = f;
f = sibling[f as usize];
}
debug_assert_ne!(bigf, EMPTY);
let fnext = sibling[bigf as usize];
if fnext != EMPTY {
if bigfprev == EMPTY {
child[i] = fnext;
} else {
sibling[bigfprev as usize] = fnext;
}
sibling[bigf as usize] = EMPTY;
sibling[fprev as usize] = bigf;
}
}
}
let mut order = vec![EMPTY; nn];
let mut k: i64 = 0;
for i in 0..nn {
if parent[i] == EMPTY && nv[i] > 0 {
k = post_tree(i, k, &mut child, &sibling, &mut order);
}
}
order
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn single_node_tree() {
let parent = [EMPTY];
let nv = [1i64];
let fsize = [0i64];
let order = postorder(1, &parent, &nv, &fsize);
assert_eq!(order, vec![0]);
}
#[test]
fn chain_orders_root_last() {
let parent = [1, 2, EMPTY];
let nv = [1, 1, 1];
let fsize = [0, 0, 0];
let order = postorder(3, &parent, &nv, &fsize);
assert_eq!(order[2], 2, "root should be visited last");
assert!(order[0] < order[2] && order[1] < order[2]);
}
#[test]
fn two_children_bigger_last() {
let parent = [EMPTY, 0, 0];
let nv = [1, 1, 1];
let fsize = [0, 1, 5];
let order = postorder(3, &parent, &nv, &fsize);
assert_eq!(order[0], 2, "root visited last, after both children");
assert!(order[2] > order[1], "bigger child (2) should be ordered after smaller (1)");
}
}