簡體   English   中英

刪除最小二叉搜索樹Python

[英]Delete min binary search tree Python

我試圖從BST刪除最小節點,所以我在樹中搜索,直到獲得最小值(當root.leftnode為None時),然后將root.rightnode設置為根本身以繼續BST。

問題是當我在執行此操作后檢查樹時,它不顯示曾經發生的刪除。

有人可以向我指出正確的方向,任何建議都值得贊賞。

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()

您可以找到樹中的所有節點以及該節點的路徑,找到最小的結果,然后遍歷生成的路徑以刪除該節點:

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

創建:

     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])

輸出:

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

您遇到的問題是root = root.rightnode僅重新綁定了局部變量root 它不會更改您對該節點具有引用的其他位置(例如樹中的父節點)。

要解決此問題,您需要更改遞歸函數的工作方式。 它應該return其父節點的左節點值,而不是期望它在上一次調用中完成所有工作。 然后,這將是節點本身,但是對於最小的節點,它將是其正確的子節點。

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

關於名稱的最后說明:使用root作為樹中隨機節點的名稱有點奇怪。 通常,一棵樹只有一個根節點,而其他節點則沒有root因為它們有父節點。 不幸的是,最常規的名稱node已經用於您的節點類。 通常,應為類指定為CapitalizedNames ,以便lowercase_names可以專門引用實例和其他變量。 不過,這只是約定俗成的( list等內置類型違反了規則)。 如果您使用標准名稱樣式,則其他人可能更容易理解您的代碼,但是Python不會強制使用它們。 它將允許您使用所需的任何名稱。 即使名稱self也不是必需的,但是如果您在沒有充分理由的情況下對方法的第一個參數使用了不同的東西(這是一個很好的理由的例子:類方法和元類的方法經常使用cls作為名稱),這將非常令人困惑的第一個參數,因為對象將是一個類)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM