Skip to content

Commit e46aaa4

Browse files
committed
Added sbst.py
1 parent a45ea27 commit e46aaa4

File tree

2 files changed

+171
-3
lines changed

2 files changed

+171
-3
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
A simple balanced search tree
22
=============
33

4-
This is a C++ implementation of a simple, balanced, binary search tree that I made as a personal project to make implementing balanced BSTs simpler. It's based on the Scapegoat tree, so it's kinda similar to it.
4+
This is a C++ and python implementation of a simple, balanced, binary search tree that I made as a personal project to make implementing balanced BSTs simpler. It's based on the Scapegoat tree, so it's kinda similar to it.
55

66
# How to use
7-
Just copy the SBST.h file and put it in your project file.
7+
Just copy the SBST.h or sbst.py file and put it in your project file.
88

9-
In your source code, to make a SBST that stores int keys, for example, use
9+
In your C++ source code, to make a SBST that stores int keys, for example, use
1010
```
1111
SBST<int> bst;
1212
```

source/sbst.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
class Node:
2+
def __init__(self, key, timer):
3+
self.key = key
4+
self.left = None
5+
self.right = None
6+
self.timer = timer
7+
8+
def getCopy(self):
9+
copy = Node(self.key, self.timer)
10+
copy.left = self.left
11+
copy.right = self.right
12+
return copy
13+
14+
class SBST:
15+
"""
16+
A simple, balanced, binary search tree.
17+
Use a K value in (0, 1).
18+
"""
19+
#---Initialize---
20+
def __init__(self, k=0.9):
21+
if not(0 < k and k < 1):
22+
raise ValueError("k must be 0 < k < 1")
23+
self.__root = None
24+
self.__k = k
25+
self.__defaultTimer = 5
26+
27+
#---Interface---
28+
def search(self, key):
29+
return self.__search(self.__root, key)
30+
31+
def insert(self, key):
32+
(self.__root, result) = self.__insert(self.__root, key)
33+
return result
34+
35+
def delete(self, key):
36+
(self.__root, result) = self.__delete(self.__root, key)
37+
return result
38+
39+
def inorder(self, callbackFunction):
40+
self.__inorder(self.__root, callbackFunction)
41+
42+
#---Private Methods---
43+
def __search(self, node, key):
44+
if node == None:
45+
return False
46+
elif key < node.key:
47+
return self.__search(node.left, key)
48+
elif node.key < key:
49+
return self.__search(node.right, key)
50+
else:
51+
return True
52+
53+
def __insert(self, node, key):
54+
if node == None:
55+
return (Node(key, self.__defaultTimer), True)
56+
elif key < node.key:
57+
(node.left, result) = self.__insert(node.left, key)
58+
elif node.key < key:
59+
(node.right, result) = self.__insert(node.right, key)
60+
else:
61+
return (node, False)
62+
63+
self.__update(node)
64+
return (node, result)
65+
66+
def __delete(self, node, key):
67+
def getMax(node):
68+
if node.right == None:
69+
return node
70+
return getMax(node.right)
71+
72+
if node == None:
73+
return (None, False)
74+
elif key < node.key:
75+
(node.left, result) = self.__delete(node.left, key)
76+
elif node.key < key:
77+
(node.right, result) = self.__delete(node.right, key)
78+
else:
79+
if node.left and node.right:
80+
node.key = getMax(node.left).key
81+
(node.left, result) = self.__delete(node.left, node.key)
82+
elif node.left:
83+
return (node.left, True)
84+
elif node.right:
85+
return (node.right, True)
86+
else:
87+
return (None, True)
88+
89+
self.__update(node)
90+
return (node, result)
91+
92+
def __update(self, node):
93+
node.timer -= 1
94+
if node.timer <= 0:
95+
self.__rebuild(node)
96+
97+
def __rebuild(self, node):
98+
if type(node) != Node:
99+
return
100+
def inorderNodeList(node, nodeList):
101+
if node == None:
102+
return
103+
inorderNodeList(node.left, nodeList)
104+
nodeList.append(node)
105+
inorderNodeList(node.right, nodeList)
106+
107+
def buildBalancedTree(nodeList, start, end, k):
108+
if start > end:
109+
return None
110+
node = nodeList[(start+end)//2]
111+
node.left = buildBalancedTree(nodeList, start, (start+end)//2-1, k)
112+
node.right = buildBalancedTree(nodeList, (start+end)//2+1, end, k)
113+
node.timer = max(self.__defaultTimer, int(k*(end-start+1)))
114+
return node
115+
116+
nodeList = []
117+
inorderNodeList(node.getCopy(), nodeList)
118+
newNode = buildBalancedTree(nodeList, 0, len(nodeList)-1, self.__k)
119+
(node.key, node.timer, node.left, node.right) = (newNode.key, newNode.timer, newNode.left, newNode.right)
120+
121+
def __inorder(self, node, callback):
122+
if node == None:
123+
return
124+
self.__inorder(node.left, callback)
125+
callback(node.key)
126+
self.__inorder(node.right, callback)
127+
128+
129+
#---Special Methods---
130+
def __repr__(self):
131+
keyList = []
132+
self.__inorder(self.__root, keyList.append)
133+
return repr(keyList)
134+
135+
def __iter__(self):
136+
def inorderYield(node):
137+
if node == None:
138+
return
139+
yield from inorderYield(node.left)
140+
yield node.key
141+
yield from inorderYield(node.right)
142+
143+
return inorderYield(self.__root)
144+
145+
#---Analysis Tools---
146+
def __debug(self, node, depth):
147+
if node == None:
148+
return
149+
self.__debug(node.left, depth+1)
150+
print(format(node.key, ">7"), format(node.timer, ">7"), format(depth, ">7"))
151+
self.__debug(node.right, depth+1)
152+
153+
def debug(self):
154+
print(" key timer depth")
155+
self.__debug(self.__root, 0)
156+
157+
#---Example Usage---
158+
if __name__ == "__main__":
159+
tree = SBST()
160+
tree.insert(10)
161+
tree.insert(15)
162+
tree.insert(20)
163+
if tree.search(20) == True:
164+
print("found")
165+
166+
tree.delete(20)
167+
if tree.search(20) == False:
168+
print("not found")

0 commit comments

Comments
 (0)