Skip to content

Commit 9b6c1a0

Browse files
committed
Btree implementation
1 parent d23a0ec commit 9b6c1a0

File tree

2 files changed

+332
-0
lines changed
  • src
    • main/java/com/thealgorithms/datastructures/trees
    • test/java/com/thealgorithms/datastructures/trees

2 files changed

+332
-0
lines changed
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
package com.thealgorithms.datastructures.trees;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
6+
public class BTree {
7+
static class BTreeNode {
8+
int[] keys;
9+
int t; // Minimum degree (defines range for number of keys)
10+
BTreeNode[] children;
11+
int n; // Current number of keys
12+
boolean leaf;
13+
14+
BTreeNode(int t, boolean leaf) {
15+
this.t = t;
16+
this.leaf = leaf;
17+
this.keys = new int[2 * t - 1];
18+
this.children = new BTreeNode[2 * t];
19+
this.n = 0;
20+
}
21+
22+
void traverse(ArrayList<Integer> result) {
23+
for (int i = 0; i < n; i++) {
24+
if (!leaf) {
25+
children[i].traverse(result);
26+
}
27+
result.add(keys[i]);
28+
}
29+
if (!leaf) {
30+
children[n].traverse(result);
31+
}
32+
}
33+
34+
BTreeNode search(int key) {
35+
int i = 0;
36+
while (i < n && key > keys[i]) {
37+
i++;
38+
}
39+
if (i < n && keys[i] == key) return this;
40+
if (leaf) return null;
41+
return children[i].search(key);
42+
}
43+
44+
void insertNonFull(int key) {
45+
int i = n - 1;
46+
if (leaf) {
47+
while (i >= 0 && keys[i] > key) {
48+
keys[i + 1] = keys[i];
49+
i--;
50+
}
51+
keys[i + 1] = key;
52+
n++;
53+
} else {
54+
while (i >= 0 && keys[i] > key) {
55+
i--;
56+
}
57+
if (children[i + 1].n == 2 * t - 1) {
58+
splitChild(i + 1, children[i + 1]);
59+
if (keys[i + 1] < key) {
60+
i++;
61+
}
62+
}
63+
children[i + 1].insertNonFull(key);
64+
}
65+
}
66+
67+
void splitChild(int i, BTreeNode y) {
68+
BTreeNode z = new BTreeNode(y.t, y.leaf);
69+
z.n = t - 1;
70+
71+
System.arraycopy(y.keys, t, z.keys, 0, t - 1);
72+
if (!y.leaf) {
73+
System.arraycopy(y.children, t, z.children, 0, t);
74+
}
75+
y.n = t - 1;
76+
77+
for (int j = n; j >= i + 1; j--) {
78+
children[j + 1] = children[j];
79+
}
80+
children[i + 1] = z;
81+
82+
for (int j = n - 1; j >= i; j--) {
83+
keys[j + 1] = keys[j];
84+
}
85+
keys[i] = y.keys[t - 1];
86+
n++;
87+
}
88+
89+
void remove(int key) {
90+
int idx = findKey(key);
91+
92+
if (idx < n && keys[idx] == key) {
93+
if (leaf) {
94+
removeFromLeaf(idx);
95+
} else {
96+
removeFromNonLeaf(idx);
97+
}
98+
} else {
99+
if (leaf) {
100+
return; // Key not found
101+
}
102+
103+
boolean flag = idx == n;
104+
if (children[idx].n < t) {
105+
fill(idx);
106+
}
107+
108+
if (flag && idx > n) {
109+
children[idx - 1].remove(key);
110+
} else {
111+
children[idx].remove(key);
112+
}
113+
}
114+
}
115+
116+
private int findKey(int key) {
117+
int idx = 0;
118+
while (idx < n && keys[idx] < key) ++idx;
119+
return idx;
120+
}
121+
122+
private void removeFromLeaf(int idx) {
123+
for (int i = idx + 1; i < n; ++i) {
124+
keys[i - 1] = keys[i];
125+
}
126+
n--;
127+
}
128+
129+
private void removeFromNonLeaf(int idx) {
130+
int key = keys[idx];
131+
if (children[idx].n >= t) {
132+
int pred = getPredecessor(idx);
133+
keys[idx] = pred;
134+
children[idx].remove(pred);
135+
} else if (children[idx + 1].n >= t) {
136+
int succ = getSuccessor(idx);
137+
keys[idx] = succ;
138+
children[idx + 1].remove(succ);
139+
} else {
140+
merge(idx);
141+
children[idx].remove(key);
142+
}
143+
}
144+
145+
private int getPredecessor(int idx) {
146+
BTreeNode cur = children[idx];
147+
while (!cur.leaf) {
148+
cur = cur.children[cur.n];
149+
}
150+
return cur.keys[cur.n - 1];
151+
}
152+
153+
private int getSuccessor(int idx) {
154+
BTreeNode cur = children[idx + 1];
155+
while (!cur.leaf) {
156+
cur = cur.children[0];
157+
}
158+
return cur.keys[0];
159+
}
160+
161+
private void fill(int idx) {
162+
if (idx != 0 && children[idx - 1].n >= t) {
163+
borrowFromPrev(idx);
164+
} else if (idx != n && children[idx + 1].n >= t) {
165+
borrowFromNext(idx);
166+
} else {
167+
if (idx != n) {
168+
merge(idx);
169+
} else {
170+
merge(idx - 1);
171+
}
172+
}
173+
}
174+
175+
private void borrowFromPrev(int idx) {
176+
BTreeNode child = children[idx];
177+
BTreeNode sibling = children[idx - 1];
178+
179+
for (int i = child.n - 1; i >= 0; --i) {
180+
child.keys[i + 1] = child.keys[i];
181+
}
182+
183+
if (!child.leaf) {
184+
for (int i = child.n; i >= 0; --i) {
185+
child.children[i + 1] = child.children[i];
186+
}
187+
}
188+
189+
child.keys[0] = keys[idx - 1];
190+
191+
if (!child.leaf) {
192+
child.children[0] = sibling.children[sibling.n];
193+
}
194+
195+
keys[idx - 1] = sibling.keys[sibling.n - 1];
196+
197+
child.n += 1;
198+
sibling.n -= 1;
199+
}
200+
201+
private void borrowFromNext(int idx) {
202+
BTreeNode child = children[idx];
203+
BTreeNode sibling = children[idx + 1];
204+
205+
child.keys[child.n] = keys[idx];
206+
207+
if (!child.leaf) {
208+
child.children[child.n + 1] = sibling.children[0];
209+
}
210+
211+
keys[idx] = sibling.keys[0];
212+
213+
for (int i = 1; i < sibling.n; ++i) {
214+
sibling.keys[i - 1] = sibling.keys[i];
215+
}
216+
217+
if (!sibling.leaf) {
218+
for (int i = 1; i <= sibling.n; ++i) {
219+
sibling.children[i - 1] = sibling.children[i];
220+
}
221+
}
222+
223+
child.n += 1;
224+
sibling.n -= 1;
225+
}
226+
227+
private void merge(int idx) {
228+
BTreeNode child = children[idx];
229+
BTreeNode sibling = children[idx + 1];
230+
231+
child.keys[t - 1] = keys[idx];
232+
233+
for (int i = 0; i < sibling.n; ++i) {
234+
child.keys[i + t] = sibling.keys[i];
235+
}
236+
237+
if (!child.leaf) {
238+
for (int i = 0; i <= sibling.n; ++i) {
239+
child.children[i + t] = sibling.children[i];
240+
}
241+
}
242+
243+
for (int i = idx + 1; i < n; ++i) {
244+
keys[i - 1] = keys[i];
245+
}
246+
247+
for (int i = idx + 2; i <= n; ++i) {
248+
children[i - 1] = children[i];
249+
}
250+
251+
child.n += sibling.n + 1;
252+
n--;
253+
}
254+
}
255+
256+
private BTreeNode root;
257+
private final int t;
258+
259+
public BTree(int t) {
260+
this.root = null;
261+
this.t = t;
262+
}
263+
264+
public void traverse(ArrayList<Integer> result) {
265+
if (root != null) root.traverse(result);
266+
}
267+
268+
public boolean search(int key) {
269+
return root != null && root.search(key) != null;
270+
}
271+
272+
public void insert(int key) {
273+
if (root == null) {
274+
root = new BTreeNode(t, true);
275+
root.keys[0] = key;
276+
root.n = 1;
277+
} else {
278+
if (root.n == 2 * t - 1) {
279+
BTreeNode s = new BTreeNode(t, false);
280+
s.children[0] = root;
281+
s.splitChild(0, root);
282+
int i = 0;
283+
if (s.keys[0] < key) i++;
284+
s.children[i].insertNonFull(key);
285+
root = s;
286+
} else {
287+
root.insertNonFull(key);
288+
}
289+
}
290+
}
291+
292+
public void delete(int key) {
293+
if (root == null) return;
294+
root.remove(key);
295+
if (root.n == 0) {
296+
root = root.leaf ? null : root.children[0];
297+
}
298+
}
299+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.thealgorithms.datastructures.trees;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
import java.util.*;
5+
import org.junit.jupiter.api.Test;
6+
7+
public class BTreeTest {
8+
9+
@Test
10+
public void testInsertSearchDelete() {
11+
BTree bTree = new BTree(3); // Minimum degree t = 3
12+
13+
int[] values = {10, 20, 5, 6, 12, 30, 7, 17};
14+
for (int val : values) {
15+
bTree.insert(val);
16+
}
17+
18+
for (int val : values) {
19+
assertTrue(bTree.search(val), "Should find inserted value: " + val);
20+
}
21+
22+
ArrayList<Integer> traversal = new ArrayList<>();
23+
bTree.traverse(traversal);
24+
assertEquals(Arrays.asList(5, 6, 7, 10, 12, 17, 20, 30), traversal);
25+
26+
bTree.delete(6);
27+
assertFalse(bTree.search(6));
28+
traversal.clear();
29+
bTree.traverse(traversal);
30+
assertEquals(Arrays.asList(5, 7, 10, 12, 17, 20, 30), traversal);
31+
}
32+
}
33+

0 commit comments

Comments
 (0)