use std::{collections::BTreeMap, sync::Arc};
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum BinaryNode {
Atomic,
Binary {
lhs: Arc<BinaryNode>,
rhs: Arc<BinaryNode>,
},
}
impl Default for BinaryNode {
fn default() -> Self {
Self::Atomic
}
}
impl BinaryNode {
pub fn atomic() -> Arc<Self> {
Arc::new(BinaryNode::Atomic)
}
pub fn binary(lhs: &Arc<Self>, rhs: &Arc<Self>) -> Arc<Self> {
Arc::new(BinaryNode::Binary { lhs: lhs.clone(), rhs: rhs.clone() })
}
pub fn nodes(&self) -> usize {
match self {
BinaryNode::Atomic => 1,
BinaryNode::Binary { lhs, rhs } => lhs.nodes() + rhs.nodes(),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct FullBinaryTrees {
cache: BTreeMap<usize, Vec<Arc<BinaryNode>>>,
}
impl FullBinaryTrees {
pub fn clear(&mut self) {
self.cache.clear();
}
pub fn inquire(&self, count: usize) -> &[Arc<BinaryNode>] {
let idx = count * 2 - 1;
match self.cache.get(&idx) {
Some(s) => s.as_slice(),
None => unreachable!("Cache must be built before query!"),
}
}
}
impl FullBinaryTrees {
pub fn build_trees(&mut self, count: usize) -> Vec<Arc<BinaryNode>> {
self.build_by_nodes(count * 2 - 1)
}
fn build_by_nodes(&mut self, count: usize) -> Vec<Arc<BinaryNode>> {
if !self.cache.contains_key(&count) {
let mut trees = vec![];
if count == 1 {
trees.push(BinaryNode::atomic());
}
else if count & 1 == 1 {
for left_sum in (1..count - 1).step_by(2) {
let right_sum = count - left_sum - 1;
let lhs = self.build_by_nodes(left_sum);
let rhs = self.build_by_nodes(right_sum);
for left_node in &lhs {
for right_node in &rhs {
let root = BinaryNode::binary(left_node, right_node);
trees.push(root);
}
}
}
}
self.cache.insert(count, trees);
}
match self.cache.get(&count) {
Some(s) => s.clone(),
None => {
vec![]
}
}
}
}