changeset 5:b4656ce03bda

Implement intra-node binary search
author Lewin Bormann <lbo@spheniscida.de>
date Tue, 05 Jul 2022 11:37:24 -0700
parents 48536f1240fc
children 507eff1f0fe6
files src/lib.rs
diffstat 1 files changed, 78 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib.rs	Tue Jul 05 09:40:05 2022 -0700
+++ b/src/lib.rs	Tue Jul 05 11:37:24 2022 -0700
@@ -2,7 +2,7 @@
 use std::cmp::Ordering;
 
 // Min. order: 3
-const ORDER: usize = 5;
+const ORDER: usize = 20;
 
 #[derive(Debug)]
 struct Node<T> {
@@ -96,24 +96,37 @@
         let mut j = 0;
         // Break once we arrived at the entry right of the correct child, if we don't return
         // earlier.
-        for i in 0..ORDER {
-            if i < ORDER - 1 {
-                if let Some(el) = self.get(node, i) {
-                    match Cmp::cmp(value, el) {
-                        Ordering::Less => {
-                            j = i;
-                            break;
+
+        if false {
+            // Comment this in if binary search within nodes makes sense. Usually it takes longer than a contiguous scan.
+            j = self.binary_node_search(node, value);
+            if j < ORDER - 1 {
+                if let Some(el) = self.get(node, j) {
+                    if Cmp::cmp(value, el) == Ordering::Equal {
+                        return Some(el);
+                    }
+                }
+            }
+        } else {
+            for i in 0..ORDER {
+                if i < ORDER - 1 {
+                    if let Some(el) = self.get(node, i) {
+                        match Cmp::cmp(value, el) {
+                            Ordering::Less => {
+                                j = i;
+                                break;
+                            }
+                            Ordering::Equal => return Some(el),
+                            Ordering::Greater => continue,
                         }
-                        Ordering::Equal => return Some(el),
-                        Ordering::Greater => continue,
+                    } else {
+                        j = i;
+                        break;
                     }
                 } else {
                     j = i;
                     break;
                 }
-            } else {
-                j = i;
-                break;
             }
         }
         if let Some(ch) = self.get_child(node, j) {
@@ -122,6 +135,40 @@
         None
     }
 
+    // Find equal or next-greater element in node array.
+    fn binary_node_search(&self, node: usize, value: &T) -> usize {
+        let mut lo = 0;
+        let mut hi = ORDER - 2 - self.free(node);
+        let mut mid = hi / 2;
+
+        while lo < hi {
+            if let Some(el) = self.get(node, mid) {
+                match Cmp::cmp(value, el) {
+                    Ordering::Less => {
+                        hi = mid;
+                        mid = lo + (hi - lo) / 2;
+                        continue;
+                    }
+                    Ordering::Equal => return mid,
+                    Ordering::Greater => {
+                        lo = mid + 1; // We already know that mid cannot be a potential result; skip it.
+                        mid = lo + (hi - lo) / 2;
+                        continue;
+                    }
+                }
+            } else {
+                // This shouldn't occur in a contiguous node.
+                unimplemented!();
+            }
+        }
+        if let Some(el) = self.get(node, lo) {
+            if Ordering::Greater == Cmp::cmp(value, el) {
+                return lo + 1;
+            }
+        }
+        return lo;
+    }
+
     /// Insert a value into an existing node, preserving the order.
     /// Requires that at least one slot be free.
     fn insert_inline(
@@ -391,7 +438,7 @@
     #[test]
     fn test_find_sequential() {
         time_test::time_test!("1000 x insert/find sequential");
-        let N = 1000;
+        let N = 100;
         let mut bt = BTree::new(N / 3);
         for i in 0..N {
             bt.insert(i);
@@ -416,4 +463,21 @@
             }
         }
     }
+
+    #[test]
+    fn test_binary_node_search() {
+        let mut bt = BTree::new(10);
+        for i in 0..super::ORDER - 5 {
+            bt.insert(i);
+        }
+
+        println!("{}", bt.debug_print());
+        assert_eq!(bt.binary_node_search(bt.root, &19), 15);
+        for i in 0..super::ORDER - 1 {
+            assert_eq!(
+                bt.binary_node_search(bt.root, &i),
+                std::cmp::min(i, super::ORDER - 5)
+            );
+        }
+    }
 }