Menghapus Node Pada Binary Search Tree

Teori Singkat

Untuk menghapus node, langkah pertama adalah mencari node tersebut. Kemudian melakukan delete node.

Ada tiga kondis penghapusan, yaitu zero, one dan two child.

Zero Child, jika node yang dihapus tidak memiliki children. Kita bisa langsung delete node tersebut. Lihat gambar-1, contoh yang akan dihapus adalah node 25.

One Child, jika node yang dihapus memiliki 1 children. Maka node children tersebut akan menjadi posisi parent (node yang dihapus). Lihat gambar-2, node yang akan dihapus adalah 70.

Two Child, jika node yang dihapus memiliki 2 children. Gunakan metoda RTFM, Right Tree Find Minimum. Jadi telusuri node di kaki kanan, cari nilai minimum. Gunakan node minimum tersebut untuk menggantikan node yang dihapus.

Lihat gambar-3, node yang akan dihapus adalah node 70. Langkah pertama telesuri kaki kanan untuk mencari node minimum, yaitu node 80. Karena node minimum, sudah dipastikan hanya memiliki kaki kanan (jika memiliki kaki kiri, node tersebut bukan node minimum).

Pindahkan node 80 untuk menggantikan node 70. Jika memiliki child, maka pindahkan child ke posisi node 80 sebelumnya.

Gambar-1 : Zero Child
Gambar-2 : One Child
Gambar-3 : Two Child

Implementasi Pada Python

Pertama kita buat helper function untuk mencari minimum node.

def findMinNode(self):
    if self.left:
        return self.left.findMinNode()
        
    return self.data

Lalu kita buat fungsi untuk delete Node

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:

            #one child or two child
            return self.left or self.right

Jangan lupa untuk menambahkan fungsi delNode pada class wrapper Tree.

def delNode(self, target):
    self.root = self.root.delNode(target)

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.data)
            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


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(str(n))+1
        return str(n)+(' '*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)

node = Node(55)

node.left = Node(25)
node.right = Node(70)

node.right.left = Node(60)
node.right.right = Node(90)

node.right.right.left = Node(80)
node.right.right.right = Node(120)

node.right.right.left.right = Node(85)

myTree = Tree(node, 'Basic BST')
myTree.printTree()
myTree.delNode(70)
myTree.printTree()
$ python tree.py
Basic BST 
                              55  
               /                             \
              25                              70
       /             \                 /             \
      _               _               60              90
   /     \         /     \         /     \         /     \
  _       _       _       _       _       _       80      120
 / \     / \     / \     / \     / \     / \     / \     / \
_   _   _   _   _   _   _   _   _   _   _   _   _   85  _   _

Basic BST
              55
       /             \
      25              80
   /     \         /     \
  _       _       60      90
 / \     / \     / \     / \
_   _   _   _   _   _   85  120

Pada program dilakukan penghapusan node 70, sesuai ekspektasi, node 80 akan menggantikan node 70, dan node 85 akan menggantikan posisi node 80.

Sharing is caring:

Leave a Comment