Skip to content

Instantly share code, notes, and snippets.

@mateor
Created November 12, 2014 23:17
Show Gist options
  • Save mateor/885eb950df7231f178a5 to your computer and use it in GitHub Desktop.
Save mateor/885eb950df7231f178a5 to your computer and use it in GitHub Desktop.
A simple B-Tree in Python that supports insert, search and print.
# coding=utf-8
"""
author = Mateor
PYTHON 3.3.5
"""
from __future__ import (nested_scopes, generators, division, absolute_import, with_statement,
print_function, unicode_literals)
class BTree(object):
"""A BTree implementation with search and insert functions. Capable of any order t."""
class Node(object):
"""A simple B-Tree Node."""
def __init__(self, t):
self.keys = []
self.children = []
self.leaf = True
# t is the order of the parent B-Tree. Nodes need this value to define max size and splitting.
self._t = t
def split(self, parent, payload):
"""Split a node and reassign keys/children."""
new_node = self.__class__(self._t)
mid_point = self.size//2
split_value = self.keys[mid_point]
parent.add_key(split_value)
# Add keys and children to appropriate nodes
new_node.children = self.children[mid_point + 1:]
self.children = self.children[:mid_point + 1]
new_node.keys = self.keys[mid_point+1:]
self.keys = self.keys[:mid_point]
# If the new_node has children, set it as internal node
if len(new_node.children) > 0:
new_node.leaf = False
parent.children = parent.add_child(new_node)
if payload < split_value:
return self
else:
return new_node
@property
def _is_full(self):
return self.size == 2 * self._t - 1
@property
def size(self):
return len(self.keys)
def add_key(self, value):
"""Add a key to a node. The node will have room for the key by definition."""
self.keys.append(value)
self.keys.sort()
def add_child(self, new_node):
"""
Add a child to a node. This will sort the node's children, allowing for children
to be ordered even after middle nodes are split.
returns: an order list of child nodes
"""
i = len(self.children) - 1
while i >= 0 and self.children[i].keys[0] > new_node.keys[0]:
i -= 1
return self.children[:i + 1]+ [new_node] + self.children[i + 1:]
def __init__(self, t):
"""
Create the B-tree. t is the order of the tree. Tree has no keys when created.
This implementation allows duplicate key values, although that hasn't been checked
strenuously.
"""
self._t = t
if self._t <= 1:
raise ValueError("B-Tree must have a degree of 2 or more.")
self.root = self.Node(t)
def insert(self, payload):
"""Insert a new key of value payload into the B-Tree."""
node = self.root
# Root is handled explicitly since it requires creating 2 new nodes instead of the usual one.
if node._is_full:
new_root = self.Node(self._t)
new_root.children.append(self.root)
new_root.leaf = False
# node is being set to the node containing the ranges we want for payload insertion.
node = node.split(new_root, payload)
self.root = new_root
while not node.leaf:
i = node.size - 1
while i > 0 and payload < node.keys[i] :
i -= 1
if payload > node.keys[i]:
i += 1
next = node.children[i]
if next._is_full:
node = next.split(node, payload)
else:
node = next
# Since we split all full nodes on the way down, we can simply insert the payload in the leaf.
node.add_key(payload)
def search(self, value, node=None):
"""Return True if the B-Tree contains a key that matches the value."""
if node is None:
node = self.root
if value in node.keys:
return True
elif node.leaf:
# If we are in a leaf, there is no more to check.
return False
else:
i = 0
while i < node.size and value > node.keys[i]:
i += 1
return self.search(value, node.children[i])
def print_order(self):
"""Print an level-order representation."""
this_level = [self.root]
while this_level:
next_level = []
output = ""
for node in this_level:
if node.children:
next_level.extend(node.children)
output += str(node.keys) + " "
print(output)
this_level = next_level
@rmadrazo97
Copy link

Will it support a delete? and preserve its integrity??

@thismusicdude
Copy link

yes, a delete function would be awesome <3

@napolanocarmine
Copy link

Don't have a delete function?

@mateor
Copy link
Author

mateor commented Jan 6, 2020

Sorry friends, the delete is left as an exercise for the user ;)

@Chaa00
Copy link

Chaa00 commented May 7, 2020

Please can you give me favor? I really need the delete function. I have an exam this week about B-tree and i couldn't resolve the delete function. Your code is really perfect thank you so much! At least a simple indication about Delete function could save me. Thank you again.

@iliopo
Copy link

iliopo commented Feb 19, 2024

Hello, this implementation is very cool but I dont think it works.
When I use the following input [0,1,2,3,4,5,6,7,8,9] I have this output:
[2, 5]
[0, 1] [3, 4] [6, 7, 8, 9]
But when you use a visualizare (such as https://people.ksp.sk/~kuko/gnarley-trees/Btree.html) the result are different? Is there something I am not understanding?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment