Skip to content

Commit f08e936

Browse files
ie-Yoshisaurvil02
andauthored
perf: Optimize BTree search using binary search (#767)
* perf: Optimize BTree search using binary search This commit optimizes the search function in the BTree implementation by replacing the linear search with a binary search algorithm. This change significantly improves the search performance, especially for large trees. Implementation details: - Modified the `search` method in the `BTree` struct - Replaced the while loop with `binary_search` method on the `keys` vector Complexity analysis: - Previous implementation: O(n) per node, where n is the number of keys - New implementation: O(log n) per node Benchmark results: - Environment: MacOS 14.5, Apple M1 Pro, 32 GB RAM - Dataset: 1,000,000 random integers for insertion - Search: 1,000,000 searches for the key 500,000 - Before: - Insertion: 3.002587333s - Search: 2.334683584s - After: - Insertion: 2.998482583s - Search: 288.659458ms Note: Insertion time remains largely unchanged, as expected. All existing tests pass with the new implementation. Benchmark code is not included in this commit. * tests: expand existing `test_search` --------- Co-authored-by: Piotr Idzik <[email protected]>
1 parent 65ca19d commit f08e936

File tree

1 file changed

+50
-27
lines changed

1 file changed

+50
-27
lines changed

src/data_structures/b_tree.rs

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -146,20 +146,16 @@ where
146146

147147
pub fn search(&self, key: T) -> bool {
148148
let mut current_node = &self.root;
149-
let mut index: isize;
150149
loop {
151-
index = isize::try_from(current_node.keys.len()).ok().unwrap() - 1;
152-
while index >= 0 && current_node.keys[index as usize] > key {
153-
index -= 1;
154-
}
155-
156-
let u_index: usize = usize::try_from(index + 1).ok().unwrap();
157-
if index >= 0 && current_node.keys[u_index - 1] == key {
158-
break true;
159-
} else if current_node.is_leaf() {
160-
break false;
161-
} else {
162-
current_node = &current_node.children[u_index];
150+
match current_node.keys.binary_search(&key) {
151+
Ok(_) => return true,
152+
Err(index) => {
153+
if current_node.is_leaf() {
154+
return false;
155+
} else {
156+
current_node = &current_node.children[index];
157+
}
158+
}
163159
}
164160
}
165161
}
@@ -169,19 +165,46 @@ where
169165
mod test {
170166
use super::BTree;
171167

172-
#[test]
173-
fn test_search() {
174-
let mut tree = BTree::new(2);
175-
tree.insert(10);
176-
tree.insert(20);
177-
tree.insert(30);
178-
tree.insert(5);
179-
tree.insert(6);
180-
tree.insert(7);
181-
tree.insert(11);
182-
tree.insert(12);
183-
tree.insert(15);
184-
assert!(tree.search(15));
185-
assert!(!tree.search(16));
168+
macro_rules! test_search {
169+
($($name:ident: $number_of_children:expr,)*) => {
170+
$(
171+
#[test]
172+
fn $name() {
173+
let mut tree = BTree::new($number_of_children);
174+
tree.insert(10);
175+
tree.insert(20);
176+
tree.insert(30);
177+
tree.insert(5);
178+
tree.insert(6);
179+
tree.insert(7);
180+
tree.insert(11);
181+
tree.insert(12);
182+
tree.insert(15);
183+
assert!(!tree.search(4));
184+
assert!(tree.search(5));
185+
assert!(tree.search(6));
186+
assert!(tree.search(7));
187+
assert!(!tree.search(8));
188+
assert!(!tree.search(9));
189+
assert!(tree.search(10));
190+
assert!(tree.search(11));
191+
assert!(tree.search(12));
192+
assert!(!tree.search(13));
193+
assert!(!tree.search(14));
194+
assert!(tree.search(15));
195+
assert!(!tree.search(16));
196+
}
197+
)*
198+
}
199+
}
200+
201+
test_search! {
202+
children_2: 2,
203+
children_3: 3,
204+
children_4: 4,
205+
children_5: 5,
206+
children_10: 10,
207+
children_60: 60,
208+
children_101: 101,
186209
}
187210
}

0 commit comments

Comments
 (0)