-
Notifications
You must be signed in to change notification settings - Fork 40
/
avl_balanced_tree.py
170 lines (145 loc) · 5.4 KB
/
avl_balanced_tree.py
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
#!/usr/bin/python
# Date: 2020-08-08
#
# Description:
# Implement AVL tree with insert and delete operations.
# AVL tree is a balanced tree in which height of left and right sub trees is
# not more than 1 for every node. This can be achieved by rotating the tree
# after every insert and delete operations if not balanced.
#
# Reference:
# http://www.geeksforgeeks.org/avl-tree-set-1-insertion/
# http://www.geeksforgeeks.org/avl-tree-set-2-deletion/
#
# Complexity:
# All operations can be done in log(n) time complexity in AVL trees.
class Node:
def __init__(self, key):
self.key = key
self.left = None
self.right = None
self.height = 1
class AVL:
def height(self, node):
"""Returns height of a node."""
if node is None:
return 0
return node.height
def get_balance_factor(self, node):
"""Return difference in heights of left and right subtree of node."""
if node is None:
return 0
return self.height(node.left) - self.height(node.right)
def right_rotate(self, y):
"""Right rotates given subtree."""
x = y.left
t = x.right
x.right = y
y.left = t
x.height = max(self.height(x.left), self.height(x.right)) + 1
y.height = max(self.height(y.left), self.height(y.right)) + 1
return x
def left_rotate(self, x):
"""Left rotates given subtree."""
y = x.right
t = y.left
x.right = t
y.left = x
x.height = max(self.height(x.left), self.height(x.right)) + 1
y.height = max(self.height(y.left), self.height(y.right)) + 1
return y
def insert(self, root, key):
"""Inserts new node in AVL tree."""
if root is None:
return Node(key)
if root.key > key:
root.left = self.insert(root.left, key)
elif root.key < key:
root.right = self.insert(root.right, key)
else:
print('Duplicate[%d] key not allowed' % key)
return root
root.height = max(self.height(root.left), self.height(root.right)) + 1
balance_factor = self.get_balance_factor(root)
print('Balance factor of node %d after inserting %d is %d' % (
root.key, key, balance_factor))
if balance_factor > 1: # Left subtree is heavy
if key < root.left.key: # Case 1: Left left case
return self.right_rotate(root)
else: # Case 2: Left right case
root.left = self.left_rotate(root.left)
return right_rotate(root)
elif balance_factor < -1: # Right subtree is heavy
if key > root.right.key: # Case 3: Right right case
return self.left_rotate(root)
else: # Case 4: Right left case
root.right = self.right_rotate(root.right)
return self.left_rotate(root)
else:
print('Subtree rooted with %d is balanced' % root.key)
return root
def find_min(self, root):
"""Returns node with min element in tree."""
while root.left:
root = root.left
return root
def delete(self, root, key):
"""Deletes a node from AVL tree."""
if root is None:
return root
if root.key > key:
root.left = self.delete(root.left, key)
elif root.key < key:
root.right = self.delete(root.right, key)
else: # Found node to be deleted
if root.left is None:
return root.right
elif root.right is None:
return root.left
else: # Node to be deleted has both childs
node = self.find_min(root.right)
root.key = node.key
root.right = self.delete(root.right, node.key)
# After deletion tree is empty
if root is None:
return root
# Update height and balance if not balanced
root.height = max(self.height(root.left), self.height(root.right)) + 1
balance_factor = self.get_balance_factor(root)
print('Balance factor of node %d after inserting %d is %d' % (
root.key, key, balance_factor))
if balance_factor > 1: # Left subtree is heavy
if key > root.left.key: # Case 1: Left left
return self.right_rotate(root)
else: # Case 2: Left right
root.left = self.left_rotate(root.left)
return self.right_rotate(root)
elif balance_factor < -1: # Right subtree is heavy
if key < root.right.key: # Case 3: Right right
return self.left_rotate(root)
else: # Case 4: Right left
root.right = self.right_rotate(root.right)
return self.left_rotate(root)
else:
print('Subtree rooted with %d is balanced' % root.key)
return root
def inorder(self, R):
if R:
self.inorder(R.left)
print('%d[%d]' % (R.key, self.get_balance_factor(R)), end=' ')
self.inorder(R.right)
def main():
root = None
avl = AVL()
for k in range(10, 0, -1):
print('\nInserting %d' % k)
root = avl.insert(root, k)
avl.inorder(root)
print()
for k in range(12):
print('\nDeleting %d' % k)
root = avl.delete(root, k)
avl.inorder(root)
print()
if __name__ == '__main__':
main()