-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAVL_tree.py
More file actions
174 lines (138 loc) · 5.23 KB
/
AVL_tree.py
File metadata and controls
174 lines (138 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import random
from TreeNode import TreeNode
# AVL tree class which supports the
# Insert operation
class AVL_Tree(object):
"""AVL Tree with insert and delete implementation.
https://en.wikipedia.org/wiki/AVL_tree"""
def __init__(self, maxWidth=2):
self.root = None
self.maxWidth = maxWidth
def __str__(self):
return str(self.root)
def raw_stringify(self):
grid = TreeNode.add_node_to_grid(self.root)
return TreeNode.simple_stringify_grid(grid)
def insert(self, key):
self.root = self._insert(self.root, key)
def _insert(self, root, key):
"""Recursive function to insert key in
subtree rooted with node and returns
new root of subtree."""
# Step 1 - Perform normal BST
if not root:
return TreeNode(key)
elif key < root.value:
root.left = self._insert(root.left, key)
else:
root.right = self._insert(root.right, key)
# Step 2 - Update the height of the
# ancestor node
root.height = 1 + max(self._get_height(root.left),
self._get_height(root.right))
# Step 3 - Get the balance factor
balance = self._get_balance(root)
# Step 4 - If the node is unbalanced,
# then try out the 4 cases
# Case 1 - Left Left
if balance > 1 and key < root.left.value:
return self._right_rotate(root)
# Case 2 - Right Right
if balance < -1 and key > root.right.value:
return self._left_rotate(root)
# Case 3 - Left Right
if balance > 1 and key > root.left.value:
root.left = self._left_rotate(root.left)
return self._right_rotate(root)
# Case 4 - Right Left
if balance < -1 and key < root.right.value:
root.right = self._right_rotate(root.right)
return self._left_rotate(root)
return root
def delete_node(self, key):
self.root = self._delete_node(self.root, key)
def _delete_node(self, root, key):
# Find the node to be deleted and remove it
if not root:
return root
elif key < root.key:
root.left = self._delete_node(root.left, key)
elif key > root.key:
root.right = self._delete_node(root.right, key)
else:
if root.left is None:
return root.right
elif root.right is None:
return root.left
temp = self.getMinValueNode(root.right)
root.key = temp.key
root.right = self._delete_node(root.right,
temp.key)
if root is None:
return root
# Update the balance factor of nodes
root.height = 1 + max(self._get_height(root.left),
self._get_height(root.right))
balanceFactor = self._get_balance(root)
# Balance the tree
if balanceFactor > 1:
if self.getBalance(root.left) >= 0:
return self._right_rotate(root)
else:
root.left = self._left_rotate(root.left)
return self._right_rotate(root)
if balanceFactor < -1:
if self.getBalance(root.right) <= 0:
return self._left_rotate(root)
else:
root.right = self.rightRotate(root.right)
return self._left_rotate(root)
return root
def _left_rotate(self, alpha):
beta = alpha.right
gamma = beta.left
# Perform rotation
beta.left = alpha
alpha.right = gamma
# Update heights
alpha.height = 1 + max(self._get_height(alpha.left ),
self._get_height(alpha.right))
beta.height = 1 + max(self._get_height(beta .left ),
self._get_height(beta .right))
# Return the new root
return beta
def _right_rotate(self, alpha):
beta = alpha.left
gamma = beta.right
# Perform rotation
beta.right = alpha
alpha.left = gamma
# Update heights
alpha.height = 1 + max(self._get_height(alpha.left ),
self._get_height(alpha.right))
beta.height = 1 + max(self._get_height(beta .left ),
self._get_height(beta .right))
# Return the new root
return beta
def _get_height(self, root):
if not root:
return 0
return root.height
def _get_balance(self, root):
if not root:
return 0
return self._get_height(root.left) - self._get_height(root.right)
if __name__ == '__main__':
tree1 = AVL_Tree()
values = (10, 20, 30, 40, 50, 25)
for val in values:
tree1.insert(val)
print(f"constructed AVL tree from {values} is")
print(f'\n{tree1}\n')
numbers = [x for x in range(1, 32 + 1)]
random.shuffle(numbers)
tree2 = AVL_Tree()
for num in numbers:
tree2.insert(num)
print(f"{min(numbers)} to {max(numbers)} in random order added to tree\n{tree2}")
print(f'\n\nRaw tree information:\n{tree2.raw_stringify()}')