changeset 2:df21e58157f3

New tree model (recursive) working somewhat
author Lewin Bormann <lbo@spheniscida.de>
date Tue, 05 Jul 2022 07:08:06 -0700
parents 04b6ed18abf3
children a94eac64aee8
files src/lib.rs
diffstat 1 files changed, 180 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib.rs	Mon Jul 04 18:14:18 2022 -0700
+++ b/src/lib.rs	Tue Jul 05 07:08:06 2022 -0700
@@ -1,7 +1,8 @@
 use ptree::TreeBuilder;
 use std::cmp::Ordering;
 
-const ORDER: usize = 5;
+// Min. order: 3
+const ORDER: usize = 4;
 
 #[derive(Debug)]
 struct Node<T> {
@@ -54,12 +55,21 @@
         &mut self.v[node].children[child]
     }
 
-    fn insert_inline(&mut self, node: usize, value: T) {
+    /// Insert a value into an existing node, preserving the order.
+    /// Requires that at least one slot be free.
+    fn insert_inline(
+        &mut self,
+        node: usize,
+        value: T,
+        left: Option<usize>,
+        right: Option<usize>,
+    ) -> usize {
         assert!(self.free(node) >= 1);
-        let node = &mut self.v[node];
+        let nodeix = node;
 
         let mut loc = ORDER - 2;
 
+        let node = &mut self.v[node];
         for i in 0..ORDER - 1 {
             if let Some(ref el) = node.entries[i] {
                 if value.cmp(el) == Ordering::Less {
@@ -75,125 +85,190 @@
 
         for i in 0..(ORDER - 2 - loc) {
             node.entries[ORDER - 2 - i] = node.entries[ORDER - 3 - i].take();
-            node.children[ORDER - 2 - i] = node.children[ORDER - 3 - i].take();
+            node.children[ORDER - 1 - i] = node.children[ORDER - 2 - i].take();
         }
         node.entries[loc] = Some(value);
+        node.children[loc] = left;
+        node.children[loc + 1] = right;
+
+        if let Some(left) = left {
+            self.v[left].parent = Some(nodeix)
+        }
+        if let Some(right) = right {
+            self.v[right].parent = Some(nodeix);
+        }
+        loc
     }
-    fn insert(&mut self, value: T) -> bool {
-        // 1. Find appropriate node
-        // 2. Find appropriate order
-        // 3. Insert or split.
 
-        // Initialize empty tree
-        if self.v.is_empty() {
-            self.v.push(Node::new(None));
-            self.v[0].entries[0] = Some(value);
-            return true;
+    /// Split a node, returning the IDs of the two new nodes and the pivot value.
+    /// Parent pointers need to be updated by caller.
+    fn split(&mut self, node: usize) -> (usize, T, usize) {
+        assert!(self.free(node) <= 1);
+        // `node` will become left node.
+        let leftix = node;
+        let rightix = self.v.len();
+
+        println!("Starting split: {:?}", self.v[node]);
+
+        let mut right = Node::<T>::new(None); // Parent updated by caller!
+
+        let pivotix = (ORDER - 1) / 2;
+        let pivot = self.get_mut(node, pivotix).take();
+
+        // Pivot-left child remains in left node.
+        for i in pivotix + 1..ORDER {
+            right.children[i - pivotix - 1] = self.get_child_mut(leftix, i).take();
+        }
+        // Make sure to move all children pointers!
+        //right.children[ORDER - pivotix] = self.get_child_mut(leftix, ORDER - 1).take();
+        for i in pivotix + 1..ORDER - 1 {
+            right.entries[i - pivotix - 1] = self.get_mut(leftix, i).take();
         }
 
-        let mut node = self.root;
-        'CHILDREN: loop {
-            // 1. Descend as long as there are feasible children.
-            // 2. Insert or split once no more children to be found.
-            let mut found = false;
-            let mut i = 0;
-            'ELEMENTS: while i < ORDER - 1 {
-                if let Some(el) = self.get(node, i) {
-                    if value.cmp(el) == Ordering::Less {
-                        found = true;
-                        break 'ELEMENTS;
-                    }
+        self.v.push(right);
+        println!(
+            "Finishing split: left {:?} right {:?} pivot {:?}",
+            self.v[leftix], self.v[rightix], pivot
+        );
+        (leftix, pivot.unwrap(), rightix)
+    }
+
+    fn is_leaf(&self, node: usize) -> bool {
+        self.v[node].children.iter().all(|c| c.is_none())
+    }
+    fn update_right_child(&mut self, node: usize, ch: usize) {
+        for i in 0..ORDER - 1 {
+            if self.get(node, i).is_none() {
+                if let Some(subch) = self.get_child(node, i) {
+                    self.update_right_child(*subch, ch);
+                    return;
                 } else {
-                    // Past last filled element.
-                    found = true;
-                    break 'ELEMENTS;
+                    *self.get_child_mut(node, i) = Some(ch);
+                    return;
                 }
-                i += 1
             }
-            // There is an element greater than `value`?
-            if let Some(child) = self.get_child(node, i) {
-                // Descend into child node.
-                node = *child;
-                continue 'CHILDREN;
-            } else if self.free(node) >= 1 {
-                self.insert_inline(node, value);
-                return true;
-            } else {
-                // We have to split.
-                //self.split(node, Some(value), i);
-                let new = self.split(node, None, 0);
-                node = new;
-                continue;
-            }
+        }
+        // This means that even the last child slot was used so far.
+        self.update_right_child(self.get_child(node, ORDER - 1).unwrap(), ch);
+    }
+
+    /// Insert & root splitting.
+    fn insert(&mut self, value: T) -> bool {
+        if let Some((l, pivot, r)) = self.insert_into(self.root, value) {
+            // Split root
+            println!("Splitting root with new children {}, {}", l, r);
+            let mut newroot = Node::new(None);
+            let rootix = self.v.len();
+            newroot.children[0] = Some(l);
+            newroot.children[1] = Some(r);
+            newroot.entries[0] = Some(pivot);
+
+            self.v[l].parent = Some(rootix);
+            self.v[r].parent = Some(rootix);
+            self.root = rootix;
+
+            self.v.push(newroot);
+            true
+        } else {
+            true
         }
     }
 
-    /// Split node `node` at `loc`, moving all values at `loc` and higher to the right node,
-    /// inserting `value` into a new parent node.
-    fn split(&mut self, node: usize, value: Option<T>, loc: usize) -> usize {
-        let leftix = node;
-        let rightix = self.v.len();
-        let topix = self.v.len() + 1;
+    /// Insert value recursively. If a split occurs, returns (left, pivot, right) tuple.
+    fn insert_into(&mut self, node: usize, value: T) -> Option<(usize, T, usize)> {
+        // BTree initialized?
+        if self.v.len() == 0 {
+            println!("Initializing");
+            self.v.push(Node::new(None));
+            self.insert_inline(self.root, value, None, None);
+            return None;
+        }
+        // Leaf node with free space? We are finished.
+        if self.is_leaf(node) && self.free(node) >= 1 {
+            println!("Leaf {} with free space", node);
+            self.insert_inline(node, value, None, None);
+            return None;
+        } else if self.is_leaf(node) && self.free(node) < 1 {
+            // Leaf node but needs to be split.
+            let (l, pivot, r) = self.split(node);
+            // Full leaf node?
+            println!("Splitting leaf {} into {} {:?} {}", node, l, pivot, r);
 
-        let mut right = Node::new(Some(topix));
-        let mut top = Node::new(self.v[node].parent);
+            // Insert value into left or right subtree.
+            match value.cmp(&pivot) {
+                Ordering::Less => assert!(self.insert_into(l, value).is_none()),
+                Ordering::Greater => assert!(self.insert_into(r, value).is_none()),
+                _ => panic!("Attempting to insert duplicate element"),
+            };
+            return Some((l, pivot, r));
+        } else {
+            // Descend into node.
+            println!("Scanning node {}", node);
 
-        // TODO: We create a top node. In reality, the pivot value is to be inserted into the
-        // existing parent node.
-        if value.is_some() {
-            // Put pivot entry into top node.
-            top.entries[0] = value;
+            let mut split = None;
+            // Find correct child.
+            for i in 0..ORDER - 1 {
+                if i < ORDER - 2 {
+                    if let Some(el) = self.get(node, i) {
+                        if value.cmp(el) == Ordering::Less {
+                            split = self.insert_into(self.get_child(node, i).unwrap(), value);
+                            break;
+                        }
+                    } else {
+                        if let Some(ch) = self.get_child(node, i) {
+                            split = self.insert_into(*ch, value);
+                            break;
+                        }
+                        panic!(
+                            "Internal node missing child? {} => {:?}",
+                            node, self.v[node]
+                        );
+                    }
+                } else {
+                    if let Some(ch) = self.get_child(node, i) {
+                        split = self.insert_into(*ch, value);
+                        break;
+                    } else {
+                        let (l, pivot, r) = self.split(node);
 
-            // Copy greater elements to right node.
-            for i in loc..ORDER - 1 {
-                right.entries[i - loc] = self.get_mut(node, i).take();
+                        // Insert value into left or right subtree.
+                        match value.cmp(&pivot) {
+                            Ordering::Less => assert!(self.insert_into(l, value).is_none()),
+                            Ordering::Greater => assert!(self.insert_into(r, value).is_none()),
+                            _ => panic!("Attempting to insert duplicate element"),
+                        };
+
+                        return Some((l, pivot, r));
+                    }
+                }
             }
 
-            // left
-            top.children[0] = Some(leftix);
-            // right
-            top.children[1] = Some(rightix);
-        } else {
-            // Split without inserting value.
-            let pivotix = (ORDER-1) / 2;
-            let pivot = self.get_mut(node, pivotix).take();
-
-            top.entries[0] = pivot;
-            // Copy greater elements to right node.
-            for i in pivotix..ORDER - 2 {
-                right.entries[i - pivotix] = self.get_mut(node, i+1).take();
-                println!("Inserting {:?} at {}", right.entries[i-pivotix], i-pivotix);
-            }
-
-            top.children[0] = Some(leftix);
-            top.children[1] = Some(rightix);
-        }
-        // Update parent.
-        {
-            if let Some(parentix) = self.v[leftix].parent {
-                let parent = &mut self.v[parentix];
-                for i in 0..ORDER {
-                    if parent.children[i] == Some(node) {
-                        parent.children[i] = Some(topix);
-                        break;
-                    }
+            println!("Split necessary? {:?}", split);
+            // Merge split if one happened below us.
+            if let Some((l, pivot, r)) = split {
+                if self.free(node) >= 1 {
+                    // We can insert the split here.
+                    self.insert_inline(node, pivot, Some(l), Some(r));
+                    return None;
+                } else {
+                    // Split this node too.
+                    let (nl, npivot, nr) = self.split(node);
+                    match pivot.cmp(&npivot) {
+                        Ordering::Less => self.insert_inline(nl, pivot, Some(l), Some(r)),
+                        Ordering::Greater => self.insert_inline(nr, pivot, Some(l), Some(r)),
+                        _ => panic!("Attempting to insert duplicate element"),
+                    };
+                    return Some((nl, npivot, nr));
                 }
             } else {
-                self.root = topix;
+                return None;
             }
         }
-        self.v[leftix].parent = Some(topix);
-        right.parent = Some(topix);
-
-        self.v.push(right);
-        self.v.push(top);
-
-        topix
     }
 }
 impl<T: std::fmt::Debug> BTree<T> {
     fn debug_print(&self) -> String {
-        let mut t = TreeBuilder::new("btree".to_string());
+        let mut t = TreeBuilder::new(format!("<{}>", self.root));
         self.print_subtree(&mut t, self.root);
         let mut o: Vec<u8> = Vec::new();
         ptree::write_tree(&t.build(), &mut o);
@@ -201,12 +276,14 @@
     }
     fn print_subtree(&self, tb: &mut TreeBuilder, node: usize) {
         let node = &self.v[node];
-        for i in 0..ORDER - 1 {
+        for i in 0..ORDER {
             if let Some(ch) = node.children[i] {
                 self.print_subtree(tb.begin_child(format!("<{}>", ch)), ch);
                 tb.end_child();
             }
-            tb.add_empty_child(format!("{:?}", node.entries[i]));
+            if i < ORDER - 1 {
+                tb.add_empty_child(format!("{:?}", node.entries[i]));
+            }
         }
     }
 }
@@ -218,7 +295,7 @@
     fn basic_test() {
         let mut bt = BTree::<i32>::new(16);
 
-        let ns = &[2,4,6,8,10,12,14,1,16,18,20,7,22,24,26,28,30];
+        let ns = &[15, 2, 21, 35, 4, 62, 31, 27, 88, 1, 12, 45, 11, 16, 23];
 
         for n in ns {
             bt.insert(*n);
@@ -226,8 +303,8 @@
             println!("root: {}", bt.root);
             println!("{}", bt.debug_print());
         }
-            for (i, e) in bt.v.iter().enumerate() {
-                println!("{} {:?}", i, e);
-            }
+        for (i, e) in bt.v.iter().enumerate() {
+            println!("{} {:?}", i, e);
+        }
     }
 }