Skip to content

Commit 0513902

Browse files
committed
AVL tree
1 parent 1314e0f commit 0513902

10 files changed

+303
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/__pycache__/
2+
/venv/

.idea/.gitignore

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/Problem-Solving-with-Algorithms-and-Data-Structures-using-Python.iml

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/inspectionProfiles/profiles_settings.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

trees/avl-tree.py

+264
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
class TreeNode:
2+
def __init__(self, key=None, value=None, parent=None, left=None, right=None,
3+
left_subtree_height: int = 0, right_subtree_height: int = 0, balance_factor: int = 0):
4+
self.key = key
5+
self.value = value
6+
self.parent = parent
7+
self.left = left
8+
self.right = right
9+
self.left_subtree_height: int = left_subtree_height
10+
self.right_subtree_height: int = right_subtree_height
11+
self.balance_factor : int = balance_factor
12+
13+
def has_left_child(self) -> bool:
14+
return self.left is not None
15+
16+
def has_right_child(self) -> bool:
17+
return self.right is not None
18+
19+
def has_both_children(self) -> bool:
20+
return self.has_left_child() and self.has_right_child()
21+
22+
def is_leaf(self) -> bool:
23+
return not self.has_left_child() and not self.has_right_child()
24+
25+
def is_root(self) -> bool:
26+
return self.parent is None
27+
28+
def has_parent(self) -> bool:
29+
return self.parent is not None
30+
31+
def is_left_child(self) -> bool:
32+
return self.parent.left == self
33+
34+
def is_right_child(self) -> bool:
35+
return self.parent.right == self
36+
37+
def find_min(self):
38+
if self is None:
39+
return None
40+
if self.has_left_child():
41+
return self.left.find_min()
42+
else:
43+
return self
44+
45+
def find_max(self):
46+
if self is None:
47+
return None
48+
node = self
49+
while node.right is not None:
50+
node = node.right
51+
return node
52+
53+
54+
class BinarySearchTree:
55+
def __init__(self):
56+
self.root: TreeNode = None
57+
self.elements: int = 0
58+
59+
def size(self) -> int:
60+
return self.elements
61+
62+
def is_empty(self) -> bool:
63+
return self.root is None
64+
65+
def put(self, key, value):
66+
if self.is_empty():
67+
self.root = TreeNode(key, value)
68+
self.elements += 1
69+
else:
70+
self._put(self.root, key, value)
71+
72+
def _put(self, root: TreeNode, key, value):
73+
if root.key == key:
74+
root.value = value
75+
elif key < root.key:
76+
if root.has_left_child():
77+
self._put(root.left, key, value)
78+
else:
79+
root.left = TreeNode(key, value, root)
80+
self.elements += 1
81+
self._update_balance_factor(root)
82+
else:
83+
if root.has_right_child():
84+
self._put(root.right, key, value)
85+
else:
86+
root.right = TreeNode(key, value, root)
87+
self.elements += 1
88+
self._update_balance_factor(root)
89+
90+
def get(self, key) -> TreeNode:
91+
if self.is_empty():
92+
return None
93+
else:
94+
return self._get(self.root, key)
95+
96+
def _get(self, root: TreeNode, key) -> TreeNode:
97+
if root.key == key:
98+
return root
99+
elif key < root.key:
100+
if root.has_left_child():
101+
return self._get(root.left, key)
102+
else:
103+
return None
104+
else:
105+
if root.has_right_child():
106+
return self._get(root.right, key)
107+
else:
108+
return None
109+
110+
def contains(self, key) -> bool:
111+
if self.is_empty():
112+
return None
113+
found: bool = False
114+
node: TreeNode = self.root
115+
while node is not None and not found:
116+
if node.key == key:
117+
found = True
118+
elif key < node.key:
119+
node = node.left
120+
else:
121+
node = node.right
122+
return found
123+
124+
def delete(self, key):
125+
node_to_delete: TreeNode = self.get(key)
126+
if node_to_delete is None:
127+
return
128+
if node_to_delete.is_root():
129+
if node_to_delete.is_leaf():
130+
self.root = None
131+
self.elements -= 1
132+
elif node_to_delete.has_both_children():
133+
max_node: TreeNode = node_to_delete.left.find_max()
134+
tmp_key = max_node.key
135+
tmp_value = max_node.value
136+
self.delete(tmp_key)
137+
# keep pointer to that node, not root, root might change
138+
node_to_delete.key = tmp_key
139+
node_to_delete.value = tmp_value
140+
else:
141+
if node_to_delete.has_left_child():
142+
self.root = node_to_delete.left
143+
else:
144+
self.root = node_to_delete.right
145+
self.root.parent = None
146+
self.elements -= 1
147+
else:
148+
parent: TreeNode = None
149+
if node_to_delete.is_leaf():
150+
parent = node_to_delete.parent
151+
if node_to_delete.is_left_child():
152+
node_to_delete.parent.left = None
153+
else:
154+
node_to_delete.parent.right = None
155+
self.elements -= 1
156+
elif node_to_delete.has_both_children():
157+
max_node: TreeNode = node_to_delete.left.find_max()
158+
tmp_key = max_node.key
159+
tmp_value = max_node.value
160+
self.delete(tmp_key)
161+
node_to_delete.key = tmp_key
162+
node_to_delete.value = tmp_value
163+
elif node_to_delete.has_left_child():
164+
parent = node_to_delete.parent
165+
self.elements -= 1
166+
if node_to_delete.is_left_child():
167+
node_to_delete.parent.left = node_to_delete.left
168+
else:
169+
node_to_delete.parent.right = node_to_delete.left
170+
node_to_delete.left.parent = node_to_delete.parent
171+
else:
172+
parent = node_to_delete.parent
173+
self.elements -= 1
174+
if node_to_delete.is_left_child():
175+
node_to_delete.parent.left = node_to_delete.right
176+
else:
177+
node_to_delete.parent.right = node_to_delete.right
178+
node_to_delete.right.parent = node_to_delete.parent
179+
if parent is not None:
180+
self._update_balance_factor(parent)
181+
182+
def find_min(self) -> TreeNode:
183+
if self.is_empty():
184+
return None
185+
node: TreeNode = self.root
186+
while node.left is not None:
187+
node = node.left
188+
return node
189+
190+
def find_max(self) -> TreeNode:
191+
if self.is_empty():
192+
return None
193+
node: TreeNode = self.root
194+
while node.right is not None:
195+
node = node.right
196+
return node
197+
198+
def _update_balance_factor(self, root: TreeNode):
199+
old_balance_factor: int = root.balance_factor
200+
if root.has_left_child():
201+
root.left_subtree_height = max(root.left.left_subtree_height, root.left.right_subtree_height) + 1
202+
else:
203+
root.left_subtree_height = 0
204+
if root.has_right_child():
205+
root.right_subtree_height = max(root.right.left_subtree_height, root.right.right_subtree_height) + 1
206+
else:
207+
root.right_subtree_height = 0
208+
root.balance_factor = root.left_subtree_height - root.right_subtree_height
209+
if root.balance_factor < -1 or root.balance_factor > 1:
210+
self._rebalance(root)
211+
return
212+
if root.balance_factor != old_balance_factor and root.has_parent():
213+
self._update(root.parent)
214+
215+
def _rebalance(self, root: TreeNode):
216+
if root.balance_factor < 0:
217+
if root.right.balance_factor > 0:
218+
self._rotate_right(root.right)
219+
else:
220+
self._rotate_left(root)
221+
else:
222+
if root.left.balance_factor < 0:
223+
self._rotate_left(root.left)
224+
else:
225+
self._rotate_right(root)
226+
227+
def _rotate_left(self, root: TreeNode):
228+
old_root: TreeNode = root
229+
new_root: TreeNode = old_root.right
230+
old_root.right = new_root.left
231+
if new_root.has_left_child():
232+
new_root.left.parent = old_root
233+
new_root.parent = old_root.parent
234+
if old_root.has_parent():
235+
if old_root.is_left_child():
236+
old_root.parent.left = new_root
237+
else:
238+
old_root.parent.right = new_root
239+
else:
240+
self.root = new_root
241+
old_root.parent = new_root
242+
new_root.left = old_root
243+
self._update_balance_factor(old_root)
244+
245+
def _rotate_right(self, root: TreeNode):
246+
old_root: TreeNode = root
247+
new_root: TreeNode = old_root.left
248+
old_root.left = new_root.right
249+
if new_root.has_right_child():
250+
new_root.right.parent = old_root
251+
new_root.parent = old_root.parent
252+
if old_root.has_parent():
253+
if old_root.is_left_child():
254+
old_root.parent.left = new_root
255+
else:
256+
old_root.parent.right = new_root
257+
else:
258+
self.root = new_root
259+
old_root.parent = new_root
260+
new_root.right = old_root
261+
self._update_balance_factor(old_root)
262+
263+
264+

trees/binary-search-tree.py

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ def _put(self, root: TreeNode, key, value):
7979
self._put(root.right, key, value)
8080
else:
8181
root.right = TreeNode(key, value, root)
82+
self.elements += 1
8283

8384
def get(self, key) -> TreeNode:
8485
if self.is_empty():

trie/trie.py

100755100644
File mode changed.

0 commit comments

Comments
 (0)