Melanjutkan dari modul sebelumnya, pada modul ini akan diimplementasikan dalam Python.
Buat fungsi baru diluar class dengan nama rotateRight dan rotateLeft.
def rotateRight(root):
pivot = root.left
reattachNode = pivot.right
root.left = reattachNode
pivot.right = root
return pivot
def rotateLeft(root):
pivot = root.right
reattachNode = pivot.left
root.right = reattachNode
pivot.left = root
return pivot
Berikut isi lengkap program tree.
class Node: def __init__(self, data): self.data = data self.left = None self.right = None def search(self, target): if self.data == target: print("Node found") return self if self.left and self.data > target: return self.left.search(target) if self.right and self.data < target: return self.right.search(target) print("No Node Found") def traversePreorder(self): print(self.data) if self.left: self.left.traversePreorder() if self.right: self.right.traversePreorder() def traverseInorder(self): if self.left: self.left.traverseInorder() print(self.data) if self.right: self.right.traverseInorder() def traversePostorder(self): if self.left: self.left.traversePostorder() if self.right: self.right.traversePostorder() print(self.data) def height(self, h=0): leftHeight = self.left.height(h+1) if self.left else h rightHeight = self.right.height(h+1) if self.right else h return max(leftHeight, rightHeight) def getNodeAtDepth(self, depth, nodes=[]): if depth==0: nodes.append(self) return nodes if self.left: self.left.getNodeAtDepth(depth-1, nodes) else: nodes.extend([None]*2**(depth-1)) if self.right: self.right.getNodeAtDepth(depth-1, nodes) else: nodes.extend([None]*2**(depth-1)) return nodes def addNode(self, val): if self.data == val: return if val < self.data: if self.left is None: self.left = Node(val) else: self.left.addNode(val) if val > self.data: if self.right is None: self.right = Node(val) else: self.right.addNode(val) def findMinNode(self): if self.left: return self.left.findMinNode() return self.data def delNode(self, target): if self.data == target: if self.left and self.right: #do RTFM minNode = self.right.findMinNode() self.data = minNode self.right = self.right.delNode(minNode) return self else: return self.left or self.right if self.right and target > self.data: self.right = self.right.delNode(target) if self.left and target < self.data: self.left = self.left.delNode(target) return self def isBalanced(self): leftHeight = self.left.height()+1 if self.left else 0 rightHeight = self.right.height()+1 if self.right else 0 return abs(leftHeight-rightHeight) < 2 def unbalanced_indikator(self): if not self.isBalanced(): return str(self.data) + "*" return str(self.data) class Tree: def __init__(self, root, name=''): self.root = root self.name = name def search(self, target): return self.root.search(target) def traversePreorder(self): self.root.traversePreorder() def traverseInorder(self): self.root.traverseInorder() def traversePostorder(self): self.root.traversePostorder() def height(self): return self.root.height() def getNodeAtDepth(self, depth): return self.root.getNodeAtDepth(depth) def _nodeToChar(self, n, space): if n is None: return '_' + (' '*space) space = space - len(n.unbalanced_indikator())+1 return n.unbalanced_indikator()+(' '*space) def printTree(self, label=''): print(self.name + ' ' + label) height = self.root.height() space = 3 width = int((2**height-1) * (space+1) +1) offset = int((width-1)/2) for depth in range(0, height+1): if depth>0: print(' '*(offset+1) + (' '*(space+2)).join(['/' + (' '*(space-2)) + '\\']*(2**(depth-1)))) row = self.root.getNodeAtDepth(depth, []) print ((' '*offset)+ ''.join([self._nodeToChar(n,space) for n in row])) space = offset + 1 offset = int(offset/2)-1 print ('') def addNode(self, val): self.root.addNode(val) def delNode(self, target): self.root = self.root.delNode(target) def rotateRight(root): pivot = root.left reattachNode = pivot.right root.left = reattachNode pivot.right = root return pivot def rotateLeft(root): pivot = root.right reattachNode = pivot.left root.right = reattachNode pivot.left = root return pivot unbalancedLL = Tree(Node(30), 'unbalanced left-left') unbalancedLL.root.left = Node(20) unbalancedLL.root.right = Node(40) unbalancedLL.root.left.left = Node(10) unbalancedLL.root.left.right = Node(25) unbalancedLL.root.left.left.left = Node(5) unbalancedLL.root.left.left.right = Node(15) unbalancedLL.printTree() unbalancedLL.root = rotateRight(unbalancedLL.root) unbalancedLL.printTree() unbalancedRR = Tree(Node(30), 'unbalanced right-right') unbalancedRR.root.left = Node(20) unbalancedRR.root.right = Node(40) unbalancedRR.root.right.left = Node(35) unbalancedRR.root.right.right = Node(60) unbalancedRR.root.right.right.left = Node(55) unbalancedRR.root.right.right.right = Node(75) unbalancedRR.printTree() unbalancedRR.root = rotateLeft(unbalancedRR.root) unbalancedRR.printTree()
Jika dijalankan maka sesuai ekspektasi program diatas berhasil melakukan rebalancing.
$ python tree.py
unbalanced left-left
30*
/ \
20 40
/ \ / \
10 25 _ _
/ \ / \ / \ / \
5 15 _ _ _ _ _ _
unbalanced left-left
20
/ \
10 30
/ \ / \
5 15 25 40
unbalanced right-right
30*
/ \
20 40
/ \ / \
_ _ 35 60
/ \ / \ / \ / \
_ _ _ _ _ _ 55 75
unbalanced right-right
40
/ \
30 60
/ \ / \
20 35 55 75
Bagaimana dengan left-right unbalanced tree? Seperti yang sudah dibahas dimodul sebelumnya, kita cukup melakukan rotasi left rotation yang kemudian diikut right rotation.
Perhatikan code dibawah melakukan dua kali rotasi yaitu, unbalancedLR.root.left = rotateLeft(unbalancedLR.root.left) dan unbalancedLR.root = rotateRight(unbalancedLR.root)
unbalancedLR = Tree(Node(30), 'unbalanced left-right')
unbalancedLR.root.left = Node(10)
unbalancedLR.root.right = Node(40)
unbalancedLR.root.left.left = Node(5)
unbalancedLR.root.left.right = Node(20)
unbalancedLR.root.left.right.left = Node(15)
unbalancedLR.root.left.right.right = Node(25)
unbalancedLR.printTree()
unbalancedLR.root.left = rotateLeft(unbalancedLR.root.left)
unbalancedLR.root = rotateRight(unbalancedLR.root)
unbalancedLR.printTree()
PS F:\Project\bst> python tree.py
unbalanced left-right
30*
/ \
10 40
/ \ / \
5 20 _ _
/ \ / \ / \ / \
_ _ 15 25 _ _ _ _
unbalanced left-right
20
/ \
10 30
/ \ / \
5 15 25 40
Untuk Latihan, silakan mencoba untuk melakukan rebalancing right-left unbalanced tree.