Mercurial > lbo > hg > btreex
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) + ); + } + } }