|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +''' |
| 3 | +An auto-balanced binary tree! |
| 4 | +''' |
| 5 | +import math |
| 6 | +import random |
| 7 | +class my_queue: |
| 8 | + def __init__(self): |
| 9 | + self.data = [] |
| 10 | + self.head = 0 |
| 11 | + self.tail = 0 |
| 12 | + def isEmpty(self): |
| 13 | + return self.head == self.tail |
| 14 | + def push(self,data): |
| 15 | + self.data.append(data) |
| 16 | + self.tail = self.tail + 1 |
| 17 | + def pop(self): |
| 18 | + ret = self.data[self.head] |
| 19 | + self.head = self.head + 1 |
| 20 | + return ret |
| 21 | + def count(self): |
| 22 | + return self.tail - self.head |
| 23 | + def print(self): |
| 24 | + print(self.data) |
| 25 | + print("**************") |
| 26 | + print(self.data[self.head:self.tail]) |
| 27 | + |
| 28 | +class my_node: |
| 29 | + def __init__(self,data): |
| 30 | + self.data = data |
| 31 | + self.left = None |
| 32 | + self.right = None |
| 33 | + self.height = 1 |
| 34 | + def getdata(self): |
| 35 | + return self.data |
| 36 | + def getleft(self): |
| 37 | + return self.left |
| 38 | + def getright(self): |
| 39 | + return self.right |
| 40 | + def getheight(self): |
| 41 | + return self.height |
| 42 | + def setdata(self,data): |
| 43 | + self.data = data |
| 44 | + return |
| 45 | + def setleft(self,node): |
| 46 | + self.left = node |
| 47 | + return |
| 48 | + def setright(self,node): |
| 49 | + self.right = node |
| 50 | + return |
| 51 | + def setheight(self,height): |
| 52 | + self.height = height |
| 53 | + return |
| 54 | + |
| 55 | +def getheight(node): |
| 56 | + if node is None: |
| 57 | + return 0 |
| 58 | + return node.getheight() |
| 59 | + |
| 60 | +def my_max(a,b): |
| 61 | + if a > b: |
| 62 | + return a |
| 63 | + return b |
| 64 | + |
| 65 | + |
| 66 | + |
| 67 | +def leftrotation(node): |
| 68 | + ''' |
| 69 | + A B |
| 70 | + / \ / \ |
| 71 | + B C Bl A |
| 72 | + / \ --> / / \ |
| 73 | + Bl Br UB Br C |
| 74 | + / |
| 75 | + UB |
| 76 | + |
| 77 | + UB = unbalanced node |
| 78 | + ''' |
| 79 | + print("left rotation node:",node.getdata()) |
| 80 | + ret = node.getleft() |
| 81 | + node.setleft(ret.getright()) |
| 82 | + ret.setright(node) |
| 83 | + h1 = my_max(getheight(node.getright()),getheight(node.getleft())) + 1 |
| 84 | + node.setheight(h1) |
| 85 | + h2 = my_max(getheight(ret.getright()),getheight(ret.getleft())) + 1 |
| 86 | + ret.setheight(h2) |
| 87 | + return ret |
| 88 | + |
| 89 | +def rightrotation(node): |
| 90 | + ''' |
| 91 | + a mirror symmetry rotation of the leftrotation |
| 92 | + ''' |
| 93 | + print("right rotation node:",node.getdata()) |
| 94 | + ret = node.getright() |
| 95 | + node.setright(ret.getleft()) |
| 96 | + ret.setleft(node) |
| 97 | + h1 = my_max(getheight(node.getright()),getheight(node.getleft())) + 1 |
| 98 | + node.setheight(h1) |
| 99 | + h2 = my_max(getheight(ret.getright()),getheight(ret.getleft())) + 1 |
| 100 | + ret.setheight(h2) |
| 101 | + return ret |
| 102 | + |
| 103 | +def rlrotation(node): |
| 104 | + ''' |
| 105 | + A A Br |
| 106 | + / \ / \ / \ |
| 107 | + B C RR Br C LR B A |
| 108 | + / \ --> / \ --> / / \ |
| 109 | + Bl Br B UB Bl UB C |
| 110 | + \ / |
| 111 | + UB Bl |
| 112 | + RR = rightrotation LR = leftrotation |
| 113 | + ''' |
| 114 | + node.setleft(rightrotation(node.getleft())) |
| 115 | + return leftrotation(node) |
| 116 | + |
| 117 | +def lrrotation(node): |
| 118 | + node.setright(leftrotation(node.getright())) |
| 119 | + return rightrotation(node) |
| 120 | + |
| 121 | + |
| 122 | +def insert_node(node,data): |
| 123 | + if node is None: |
| 124 | + return my_node(data) |
| 125 | + if data < node.getdata(): |
| 126 | + node.setleft(insert_node(node.getleft(),data)) |
| 127 | + if getheight(node.getleft()) - getheight(node.getright()) == 2: #an unbalance detected |
| 128 | + if data < node.getleft().getdata(): #new node is the left child of the left child |
| 129 | + node = leftrotation(node) |
| 130 | + else: |
| 131 | + node = rlrotation(node) #new node is the right child of the left child |
| 132 | + else: |
| 133 | + node.setright(insert_node(node.getright(),data)) |
| 134 | + if getheight(node.getright()) - getheight(node.getleft()) == 2: |
| 135 | + if data < node.getright().getdata(): |
| 136 | + node = lrrotation(node) |
| 137 | + else: |
| 138 | + node = rightrotation(node) |
| 139 | + h1 = my_max(getheight(node.getright()),getheight(node.getleft())) + 1 |
| 140 | + node.setheight(h1) |
| 141 | + return node |
| 142 | + |
| 143 | +def getRightMost(root): |
| 144 | + while root.getright() is not None: |
| 145 | + root = root.getright() |
| 146 | + return root.getdata() |
| 147 | +def getLeftMost(root): |
| 148 | + while root.getleft() is not None: |
| 149 | + root = root.getleft() |
| 150 | + return root.getdata() |
| 151 | + |
| 152 | +def del_node(root,data): |
| 153 | + if root.getdata() == data: |
| 154 | + if root.getleft() is not None and root.getright() is not None: |
| 155 | + temp_data = getLeftMost(root.getright()) |
| 156 | + root.setdata(temp_data) |
| 157 | + root.setright(del_node(root.getright(),temp_data)) |
| 158 | + elif root.getleft() is not None: |
| 159 | + root = root.getleft() |
| 160 | + else: |
| 161 | + root = root.getright() |
| 162 | + elif root.getdata() > data: |
| 163 | + if root.getleft() is None: |
| 164 | + print("No such data") |
| 165 | + return root |
| 166 | + else: |
| 167 | + root.setleft(del_node(root.getleft(),data)) |
| 168 | + elif root.getdata() < data: |
| 169 | + if root.getright() is None: |
| 170 | + return root |
| 171 | + else: |
| 172 | + root.setright(del_node(root.getright(),data)) |
| 173 | + if root is None: |
| 174 | + return root |
| 175 | + if getheight(root.getright()) - getheight(root.getleft()) == 2: |
| 176 | + if getheight(root.getright().getright()) > getheight(root.getright().getleft()): |
| 177 | + root = rightrotation(root) |
| 178 | + else: |
| 179 | + root = lrrotation(root) |
| 180 | + elif getheight(root.getright()) - getheight(root.getleft()) == -2: |
| 181 | + if getheight(root.getleft().getleft()) > getheight(root.getleft().getright()): |
| 182 | + root = leftrotation(root) |
| 183 | + else: |
| 184 | + root = rlrotation(root) |
| 185 | + height = my_max(getheight(root.getright()),getheight(root.getleft())) + 1 |
| 186 | + root.setheight(height) |
| 187 | + return root |
| 188 | + |
| 189 | +class AVLtree: |
| 190 | + def __init__(self): |
| 191 | + self.root = None |
| 192 | + def getheight(self): |
| 193 | +# print("yyy") |
| 194 | + return getheight(self.root) |
| 195 | + def insert(self,data): |
| 196 | + print("insert:"+str(data)) |
| 197 | + self.root = insert_node(self.root,data) |
| 198 | + |
| 199 | + def del_node(self,data): |
| 200 | + print("delete:"+str(data)) |
| 201 | + if self.root is None: |
| 202 | + print("Tree is empty!") |
| 203 | + return |
| 204 | + self.root = del_node(self.root,data) |
| 205 | + def traversale(self): #a level traversale, gives a more intuitive look on the tree |
| 206 | + q = my_queue() |
| 207 | + q.push(self.root) |
| 208 | + layer = self.getheight() |
| 209 | + if layer == 0: |
| 210 | + return |
| 211 | + cnt = 0 |
| 212 | + while not q.isEmpty(): |
| 213 | + node = q.pop() |
| 214 | + space = " "*int(math.pow(2,layer-1)) |
| 215 | + print(space,end = "") |
| 216 | + if node is None: |
| 217 | + print("*",end = "") |
| 218 | + q.push(None) |
| 219 | + q.push(None) |
| 220 | + else: |
| 221 | + print(node.getdata(),end = "") |
| 222 | + q.push(node.getleft()) |
| 223 | + q.push(node.getright()) |
| 224 | + print(space,end = "") |
| 225 | + cnt = cnt + 1 |
| 226 | + for i in range(100): |
| 227 | + if cnt == math.pow(2,i) - 1: |
| 228 | + layer = layer -1 |
| 229 | + if layer == 0: |
| 230 | + print() |
| 231 | + print("*************************************") |
| 232 | + return |
| 233 | + print() |
| 234 | + break |
| 235 | + print() |
| 236 | + print("*************************************") |
| 237 | + return |
| 238 | + |
| 239 | + def test(self): |
| 240 | + getheight(None) |
| 241 | + print("****") |
| 242 | + self.getheight() |
| 243 | +if __name__ == "__main__": |
| 244 | + t = AVLtree() |
| 245 | + t.traversale() |
| 246 | + l = list(range(10)) |
| 247 | + random.shuffle(l) |
| 248 | + for i in l: |
| 249 | + t.insert(i) |
| 250 | + t.traversale() |
| 251 | + |
| 252 | + random.shuffle(l) |
| 253 | + for i in l: |
| 254 | + t.del_node(i) |
| 255 | + t.traversale() |
0 commit comments