简体   繁体   中英

Delete min binary search tree Python

I am trying to delete the minimum node from a BST, so I search through the tree until I get the min (when root.leftnode is None) and then set root.rightnode to the root itself to continue the BST.

The issue is when I check the tree after doing this it does not show the deletion ever occurred.

Could someone point me in the right direction please, any advice is appreciated.

class node():

    def __init__(self, key, data):

        self.data = data
        self.key = key
        self.leftnode = None
        self.rightnode = None
        self.count = 1


class binarysearch():

    def __init__(self):

        self.size = 0
        self.rootnode = None

    def insert(self, key, data):

        if self.rootnode is None:
            self.rootnode = node(key, data)
        else:
            self.insertnode(self.rootnode, key, data)

    def getroot(self):

        return self.rootnode

    def insertnode(self, root, key, data):

            if root.key == key:
                root.data = data

            elif key < root.key:
                if root.leftnode is None:                    
                    root.leftnode = node(key, data)
                else:
                    self.insertnode(root.leftnode, key, data)
            else:
                if root.rightnode is None:
                    root.rightnode = node(key, data)
                else:
                    self.insertnode(root.rightnode, key, data)

            root.count = 1 + self.sizenode(root.leftnode) + self.sizenode(root.rightnode)

    def inorder(self, root):

        if root is not None:

            self.inorder(root.leftnode)
            print(root.key)
            self.inorder(root.rightnode)

    def deletemin(self):

        if self.rootnode is None:
            print("No nodes exist")
        else:
            self.deleteminnode(self.rootnode.leftnode)

    def deleteminnode(self, root):

        if root.leftnode is not None:
            self.deleteminnode(root.leftnode)
        else:
            print (root.key, "deleted")
            root = root.rightnode


if __name__ == '__main__':

    a = binarysearch()
    a.insert(7,7)
    a.insert(1,1)
    a.insert(8,8)
    a.insert(3,3)
    a.insert(9,9)
    a.insert(2,2)
    a.insert(4,4)
    a.insert(11,11)
    a.insert(10,10)
    a.deletemin()
    a.getnodes()

You can find all the nodes in the tree, along with the path to the node, find the minimum of the results, and then traverse the generated path to delete the node:

class Tree:
  def __init__(self, **kwargs):
    self.__dict__ = {i:kwargs.get(i) for i in ['val', 'left', 'right']}
  def get_nodes(self, current = []):
    yield [''.join(current), self.val] 
    yield from getattr(self.right, 'get_nodes', lambda _:[])(current+['1'])
    yield from getattr(self.left, 'get_nodes', lambda _:[])(current+['0'])
  def __iter__(self):
    yield self.val
    yield from [[], self.left][bool(self.left)]
    yield from [[], self.right][bool(self.right)]
  def _insert_back(self, _v):
    if not self.val:
      self.val = _v
    else:
      if _v < self.val:
         getattr(self.left, '_insert_back', lambda x:setattr(x, 'left', Tree(val=x)))(_v)
      else:
         getattr(self.right, '_insert_back', lambda x:setattr(x, 'right', Tree(val=x)))(_v)
  def remove(self, _path, _to_val, last=None):
     '''_to_val: if _to_val is None, then the item is removed. If not, the node value is set to _to_val'''
     if _path:
       getattr(self, ['left', 'right'][int(_path[0])]).remove(_path[1:], _to_val, last = self)
     else:
       if _to_val is None:
         last.left = None
         last.right = None
         for i in [[], self.left][bool(self.left)]:
           last._insert_back(i)
         for i in [[], self.right][bool(self.right)]:
            last._insert_back(i)
       else:
         self.val = _to_val

Creating:

     7 
  5     9
4   6  8  10
            12

t = Tree(val = 7, left=Tree(val = 5, left=Tree(val=4), right=Tree(val=6)), right=Tree(val=9, left=Tree(val=8), right=Tree(val=10, right=Tree(val=12))))
path, _to_remove = min(t.get_nodes(), key=lambda x:x[-1])
print(f'Removing {_to_remove}')
t.remove(path, None)
print([i for i in t])

Output:

4
[7, 5, 9, 8, 10, 12]

The issue you have is that root = root.rightnode only rebinds the local variable root . It doesn't change the other places you have references to that node (such as its parent in the tree).

To fix this, you need to change how your recursive function works. Rather than expecting it to do all the work in the last call, it should instead return the value that should be the left node of its parent. Of then that will be the node itself, but for the minimum node, it will be its right child instead.

def deletemin(self):
    if self.rootnode is None:
        print("No nodes exist")
    else:
        self.rootnode = self.deleteminnode(self.rootnode)

def deleteminnode(self, root):
    if root.leftnode is not None:
        root.leftnode = self.deleteminnode(root.leftnode)
        return root
    else:
        return root.rightnode

A final note regarding names: It's a bit weird to use root as the name of a random node within the tree. Usually a tree has just the one root node, and others nodes aren't called root since they have parents. Unfortunately, the most conventional name node is already being used for your node class. Normally classes should be given CapitalizedNames , so that lowercase_names can exclusively refer to instances and other variables. This is just convention though (and builtin types like list break the rules). It might be easier for others to understand your code if you use standard name styles, but Python doesn't enforce them. It will allow you to use whatever names you want. Even the name self is not a requirement, though it would be very confusing if you used something different for the first argument of a method without a good reason (an example of a good reason: classmethods and methods of metaclasses often use cls as the name of their first arguments, since the object will be a class).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM