Skip to content

Commit 237d88f

Browse files
feat: Add btree with insertion, deletion, and search (#703)
* feat: Add btree with insertion, deletion, and search * Lazy allocate root and handle cases with null root * Fix formatting --------- Co-authored-by: Rak Laptudirm <[email protected]>
1 parent 3f2fa29 commit 237d88f

File tree

2 files changed

+488
-0
lines changed

2 files changed

+488
-0
lines changed

structure/tree/btree.go

+355
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
// B-tree is a self balancing tree that promotes data locality.
2+
// For more details, see https://en.wikipedia.org/wiki/B-tree
3+
4+
package tree
5+
6+
import "github.com/TheAlgorithms/Go/constraints"
7+
8+
type BTreeNode[T constraints.Ordered] struct {
9+
keys []T
10+
children []*BTreeNode[T]
11+
numKeys int
12+
isLeaf bool
13+
}
14+
15+
type BTree[T constraints.Ordered] struct {
16+
root *BTreeNode[T]
17+
maxKeys int
18+
}
19+
20+
func minKeys(maxKeys int) int {
21+
return (maxKeys - 1) / 2
22+
}
23+
24+
func NewBTreeNode[T constraints.Ordered](maxKeys int, isLeaf bool) *BTreeNode[T] {
25+
if maxKeys <= 0 {
26+
panic("BTree maxKeys cannot be zero")
27+
}
28+
return &BTreeNode[T]{
29+
keys: make([]T, maxKeys),
30+
children: make([]*BTreeNode[T], maxKeys+1),
31+
isLeaf: isLeaf,
32+
}
33+
}
34+
35+
func NewBTree[T constraints.Ordered](maxKeys int) *BTree[T] {
36+
if maxKeys <= 2 {
37+
panic("Must be >= 3 keys")
38+
}
39+
return &BTree[T]{
40+
root: nil,
41+
maxKeys: maxKeys,
42+
}
43+
}
44+
45+
func (node *BTreeNode[T]) Verify(tree *BTree[T]) {
46+
minKeys := minKeys(tree.maxKeys)
47+
if node != tree.root && node.numKeys < minKeys {
48+
panic("node has too few keys")
49+
} else if node.numKeys > tree.maxKeys {
50+
panic("node has too many keys")
51+
}
52+
}
53+
54+
func (node *BTreeNode[T]) IsFull(maxKeys int) bool {
55+
return node.numKeys == maxKeys
56+
}
57+
58+
func (node *BTreeNode[T]) Search(key T) bool {
59+
i := 0
60+
for ; i < node.numKeys; i++ {
61+
if key == node.keys[i] {
62+
return true
63+
}
64+
if key < node.keys[i] {
65+
break
66+
}
67+
}
68+
if node.isLeaf {
69+
return false
70+
}
71+
return node.children[i].Search(key)
72+
}
73+
74+
func (tree *BTree[T]) Search(key T) bool {
75+
if tree.root == nil {
76+
return false
77+
}
78+
return tree.root.Search(key)
79+
}
80+
81+
func (node *BTreeNode[T]) InsertKeyChild(key T, child *BTreeNode[T]) {
82+
i := node.numKeys
83+
node.children[i+1] = node.children[i]
84+
for ; i > 0; i-- {
85+
if key > node.keys[i-1] {
86+
node.keys[i] = key
87+
node.children[i] = child
88+
break
89+
}
90+
node.keys[i] = node.keys[i-1]
91+
node.children[i] = node.children[i-1]
92+
}
93+
if i == 0 {
94+
node.keys[0] = key
95+
node.children[0] = child
96+
}
97+
node.numKeys++
98+
}
99+
100+
func (node *BTreeNode[T]) Append(key T, child *BTreeNode[T]) {
101+
node.keys[node.numKeys] = key
102+
node.children[node.numKeys+1] = child
103+
node.numKeys++
104+
}
105+
106+
// Add all of other's keys starting from idx and children starting from idx + 1
107+
func (node *BTreeNode[T]) Concat(other *BTreeNode[T], idx int) {
108+
for i := 0; i < other.numKeys-idx; i++ {
109+
node.keys[node.numKeys+i] = other.keys[i+idx]
110+
node.children[node.numKeys+i+1] = other.children[i+idx+1]
111+
}
112+
node.numKeys += other.numKeys - idx
113+
}
114+
115+
// Transform:
116+
//
117+
// A B
118+
// |
119+
//
120+
// a b c d
121+
//
122+
// Into:
123+
//
124+
// A c B
125+
// / \
126+
//
127+
// a b d
128+
func (parent *BTreeNode[T]) Split(idx int, maxKeys int) {
129+
child := parent.children[idx]
130+
midKeyIndex := maxKeys / 2
131+
rightChild := NewBTreeNode[T](maxKeys, child.isLeaf)
132+
rightChild.Concat(child, midKeyIndex+1)
133+
rightChild.children[0] = child.children[midKeyIndex+1]
134+
135+
// Reuse child as the left node
136+
child.numKeys = midKeyIndex
137+
138+
// Insert the child's mid index to the parent
139+
for i := parent.numKeys; i > idx; i-- {
140+
parent.keys[i] = parent.keys[i-1]
141+
parent.children[i+1] = parent.children[i]
142+
}
143+
parent.keys[idx] = child.keys[midKeyIndex]
144+
parent.children[idx] = child
145+
parent.children[idx+1] = rightChild
146+
parent.numKeys += 1
147+
}
148+
149+
func (node *BTreeNode[T]) InsertNonFull(tree *BTree[T], key T) {
150+
node.Verify(tree)
151+
if node.IsFull(tree.maxKeys) {
152+
panic("Called InsertNonFull() with a full node")
153+
}
154+
155+
if node.isLeaf {
156+
// Node is a leaf. Directly insert the key.
157+
node.InsertKeyChild(key, nil)
158+
return
159+
}
160+
161+
// Find the child node to insert into
162+
i := 0
163+
for ; i < node.numKeys; i++ {
164+
if key < node.keys[i] {
165+
break
166+
}
167+
}
168+
169+
if node.children[i].IsFull(tree.maxKeys) {
170+
node.Split(i, tree.maxKeys)
171+
if key > node.keys[i] {
172+
i++
173+
}
174+
}
175+
node.children[i].InsertNonFull(tree, key)
176+
}
177+
178+
func (tree *BTree[T]) Insert(key T) {
179+
if tree.root == nil {
180+
tree.root = NewBTreeNode[T](tree.maxKeys, true)
181+
tree.root.keys[0] = key
182+
tree.root.numKeys = 1
183+
return
184+
}
185+
186+
if tree.root.IsFull(tree.maxKeys) {
187+
newRoot := NewBTreeNode[T](tree.maxKeys, false)
188+
newRoot.numKeys = 0
189+
newRoot.children[0] = tree.root
190+
newRoot.Split(0, tree.maxKeys)
191+
tree.root = newRoot
192+
}
193+
tree.root.InsertNonFull(tree, key)
194+
}
195+
196+
func (node *BTreeNode[T]) DeleteIthKey(i int) {
197+
if i >= node.numKeys {
198+
panic("deleting out of bounds key")
199+
}
200+
for j := i; j < node.numKeys-1; j++ {
201+
node.keys[j] = node.keys[j+1]
202+
node.children[j+1] = node.children[j+2]
203+
}
204+
node.numKeys--
205+
}
206+
207+
// Transform:
208+
//
209+
// A B C
210+
// / \
211+
// a b
212+
//
213+
// Into:
214+
//
215+
// A C
216+
// |
217+
//
218+
// a B c
219+
func (node *BTreeNode[T]) Merge(idx int) {
220+
if node.isLeaf {
221+
panic("cannot merge when leaf node is parent")
222+
}
223+
left := node.children[idx]
224+
right := node.children[idx+1]
225+
left.Append(node.keys[idx], right.children[0])
226+
left.Concat(right, 0)
227+
node.DeleteIthKey(idx)
228+
}
229+
230+
func (node *BTreeNode[T]) Min() T {
231+
if node.isLeaf {
232+
return node.keys[0]
233+
}
234+
return node.children[0].Min()
235+
}
236+
237+
func (node *BTreeNode[T]) Max() T {
238+
if node.isLeaf {
239+
return node.keys[node.numKeys-1]
240+
}
241+
return node.children[node.numKeys].Max()
242+
}
243+
244+
func (node *BTreeNode[T]) Delete(tree *BTree[T], key T) {
245+
node.Verify(tree)
246+
if node.isLeaf {
247+
// Case 1: Node is a leaf. Directly delete the key.
248+
for i := 0; i < node.numKeys; i++ {
249+
if key == node.keys[i] {
250+
node.DeleteIthKey(i)
251+
return
252+
}
253+
}
254+
return
255+
}
256+
257+
minKeys := minKeys(tree.maxKeys)
258+
i := 0
259+
for ; i < node.numKeys; i++ {
260+
if key == node.keys[i] {
261+
// Case 2: key exists in a non-leaf node
262+
left := node.children[i]
263+
right := node.children[i+1]
264+
if left.numKeys > minKeys {
265+
// Replace the key we want to delete with the max key from the left
266+
// subtree. Then delete that key from the left subtree.
267+
// A B C
268+
// /
269+
// a b c
270+
//
271+
// If we want to delete `B`, then replace `B` with `c`, and delete `c` in the subtree.
272+
// A c C
273+
// /
274+
// a b
275+
replacementKey := left.Max()
276+
node.keys[i] = replacementKey
277+
left.Delete(tree, replacementKey)
278+
} else if right.numKeys > minKeys {
279+
// Replace the key we want to delete with the min key from the right
280+
// subtree. Then delete that key in the right subtree. Mirrors the
281+
// transformation above for replacing from the left subtree.
282+
replacementKey := right.Min()
283+
node.keys[i] = replacementKey
284+
right.Delete(tree, replacementKey)
285+
} else {
286+
// Both left and right subtrees have the minimum number of keys. Merge
287+
// the left tree, the deleted key, and the right tree together into the
288+
// left tree. Then recursively delete the key in the left tree.
289+
if left.numKeys != minKeys || right.numKeys != minKeys {
290+
panic("nodes should not have less than the minimum number of keys")
291+
}
292+
node.Merge(i)
293+
left.Delete(tree, key)
294+
}
295+
return
296+
}
297+
298+
if key < node.keys[i] {
299+
break
300+
}
301+
}
302+
303+
// Case 3: key may exist in a child node.
304+
child := node.children[i]
305+
if child.numKeys == minKeys {
306+
// Before we recurse into the child node, make sure it has more than
307+
// the minimum number of keys.
308+
if i > 0 && node.children[i-1].numKeys > minKeys {
309+
// Take a key from the left sibling
310+
// Transform:
311+
// A B C
312+
// / \
313+
// a b c
314+
//
315+
// Into:
316+
// A b C
317+
// / \
318+
// a B c
319+
left := node.children[i-1]
320+
child.InsertKeyChild(node.keys[i-1], left.children[left.numKeys])
321+
node.keys[i-1] = left.keys[left.numKeys-1]
322+
left.numKeys--
323+
} else if i < node.numKeys && node.children[i+1].numKeys > minKeys {
324+
// Take a key from the right sibling. Mirrors the transformation above for taking a key from the left sibling.
325+
right := node.children[i+1]
326+
child.Append(node.keys[i], right.children[0])
327+
node.keys[i] = right.keys[0]
328+
right.children[0] = right.children[1]
329+
right.DeleteIthKey(0)
330+
} else {
331+
if i == 0 {
332+
// Merge with right sibling
333+
node.Merge(i)
334+
} else {
335+
// Merge with left sibling
336+
node.Merge(i - 1)
337+
child = node.children[i-1]
338+
}
339+
}
340+
}
341+
if child.numKeys == minKeys {
342+
panic("cannot delete key from node with minimum number of keys")
343+
}
344+
child.Delete(tree, key)
345+
}
346+
347+
func (tree *BTree[T]) Delete(key T) {
348+
if tree.root == nil {
349+
return
350+
}
351+
tree.root.Delete(tree, key)
352+
if tree.root.numKeys == 0 {
353+
tree.root = tree.root.children[0]
354+
}
355+
}

0 commit comments

Comments
 (0)