use std::collections::hash_map::Entry;
use std::collections::HashMap;
#[derive(Debug)]
pub struct BKTree<T> {
root: Option<Box<BKNode<T>>>,
len: usize,
}
#[derive(Debug)]
struct BKNode<T> {
key: u32,
payload: T,
children: HashMap<u32, Box<BKNode<T>>>,
}
impl<T> Default for BKTree<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> BKTree<T> {
#[must_use]
pub fn new() -> Self {
Self { root: None, len: 0 }
}
#[must_use]
pub fn len(&self) -> usize {
self.len
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn add(&mut self, key: u32, payload: T) {
self.len += 1;
match &mut self.root {
None => {
self.root = Some(Box::new(BKNode {
key,
payload,
children: HashMap::new(),
}));
}
Some(root) => {
let mut node: &mut BKNode<T> = root;
loop {
let d = (node.key ^ key).count_ones();
match node.children.entry(d) {
Entry::Occupied(slot) => {
node = slot.into_mut();
}
Entry::Vacant(slot) => {
slot.insert(Box::new(BKNode {
key,
payload,
children: HashMap::new(),
}));
return;
}
}
}
}
}
}
#[must_use]
pub fn query(&self, key: u32, radius: u32) -> Vec<(u32, &T)> {
let mut results: Vec<(u32, &T)> = Vec::new();
let mut stack: Vec<&BKNode<T>> = Vec::new();
if let Some(root) = &self.root {
stack.push(root);
}
while let Some(node) = stack.pop() {
let d = (node.key ^ key).count_ones();
if d <= radius {
results.push((d, &node.payload));
}
let lo = d.saturating_sub(radius);
let hi = d.saturating_add(radius);
for (&edge, child) in &node.children {
if edge >= lo && edge <= hi {
stack.push(child);
}
}
}
results.sort_by_key(|&(d, _)| d);
results
}
}