簡體   English   中英

如何刪除二進制搜索樹的所有節點

[英]How to delete all nodes of a Binary Search Tree

我正在嘗試編寫代碼以刪除BST的所有節點(每個節點只有三個屬性,left,right和data,沒有父指針)。 以下代碼是我想出的,它僅刪除樹的右半部分,而保留左半部分不變。 我該如何修改它以使左半部分也被刪除(以便最終我只剩下沒有左或右子樹的根節點)?

def delete(root):
    global last
    if root:
     delete(root.left)
     delete(root.right)
     if not (root.left or root.right):
        last = root
     elif root.left == last:
        root.left = None
     else:
        root.right = None

其次,有人可以使用堆棧或其他相關數據結構來建議一種迭代方法嗎?

如果要刪除兩個子樹,則無需遞歸。 只需將root.leftroot.right設置為None然后讓垃圾收集器來處理它們。 確實,不必首先設置delete功能,只需設置root = None完成!

編輯:如果您需要對數據值運行清除代碼,如果GC做得不夠好,您可能需要遍歷樹以獲取所有數據。 確實沒有必要刪除樹中的鏈接,但是我也將采取適當的措施:

def delete(node):
    if node:
        node.data.cleanup() # run data value cleanup code

        delete(node.left)   # recurse
        delete(node.right)

        node.data = None    # clear pointers (not really necessary)
        node.left = None
        none.right = None

您還詢問了遍歷樹的迭代方法,這種方法稍微復雜一些。 這是一種使用deque (作為堆棧)遍歷祖先的方法:

from collections import deque

def delete_iterative(node):
    stack = deque()
    last = None

    # start up by pushing nodes to the stack until reaching leftmost node
    while node:
        stack.append(node)
        node = node.left

    # the main loop
    while stack:
        node = stack.pop()

        # should we expand the right subtree?
        if node.right && node.right != last: # yes
            stack.append(node)
            node = node.right

            while node: # expand to find leftmost node in right subtree
                stack.append(node)
                node = node.left

        else: # no, we just came from there (or it doesn't exist)
            # delete node's contents
            node.data.cleanup()

            node.data = None # clear pointers (not really necessary)
            node.left = None
            node.right = None

            # let our parent know that it was us it just visited
            last = node

Blckknght關於垃圾回收是正確的,但是如果您想進行比示例所建議的更為復雜的清理,或者理解為什么您的代碼不起作用,我將提供一個附加的答案:

您的問題似乎是elif node.left == last檢查。

我不確定您的last變量是用來做什么的,或者它背后的邏輯是什么。
但是問題在於node.left幾乎永遠不會等於last (如果兩個子節點都已經設置為None ,則僅將節點分配給last變量,對於任何有趣的節點(具有子節點的節點)來說,它們都不是。 )。

如果看一下代碼,您會發現如果node.left不等於last只有正確的孩子被設置為None ,因此只有子樹的右邊被刪除。

我不知道python,但這應該可以工作:

def delete(node):
    if node:

        # recurse: visit all nodes in the two subtrees
        delete(node.left)           
        delete(node.right)

        # after both subtrees have been visited, set pointers of this node to None
        node.left = None
        node.right = None

(我把你的重命名的自由root參數node ,因為給該函數的節點不一定是樹的根節點。)

使用堆棧的迭代后遍歷可能看起來像這樣:

def is_first_visit(cur, prev):
    return prev is None or prev.left is cur or prev.right is cur

def visit_tree(root):
    if root:
        todo = [root]
        previous = None
        while len(todo):
            node = todo[-1]
            if is_first_visit(node, previous):
                # add one of our children to the stack
                if node.left: 
                    todo.append(node.left)
                elif node.right:
                    todo.append(node.right)
                # now set previous to ourself and continue
            elif previous is node.left:
                # we've done the left subtree, do right subtree if any
                if node.right:
                    todo.append(node.right)
            else: 
                # previous is either node.right (we've visited both sub-trees)
                # or ourself (we don't have a right subtree)
                do_something(node)
                todo.pop()
            previous = node

do_something做您想調用的“實際上刪除此節點”。

您可以通過在每個節點上設置一個屬性來聲明它是否已經調用過do_something來做一些簡單的事情,但是顯然,如果您的節點上有__slots__或其他內容,並且您不希望這樣做,該方法就不能很好地工作修改節點類型以允許該標志。

我不確定在遞歸調用之后您對這些條件做什么,但是我認為這應該足夠了:

def delete(root):
  if root:
    delete(root.left)
    delete(root.right)

    root = None

正如注釋中指出的那樣,Python不會通過引用傳遞參數。 在這種情況下,您可以像這樣在Python中完成這項工作:

def delete(root):
  if root:
    delete(root.left)
    delete(root.right)

    root.left = None
    root.right = None

Usage:
delete(root)
root = None

至於迭代方法,您可以嘗試一下。 這是偽代碼,我不懂python。 基本上,我們進行BF搜索。

delete(root):
  make an empty queue Q
  Q.push(root)
  while not Q.empty:
    c = Q.popFront()
    Q.push(c.left, c.right)
    c = None

同樣,如果您將根用作功能,則默認情況下不會修改根,但是它將刪除所有其他節點。 您可以在函數調用之后將根設置為“無”,或者刪除參數並使用全局根變量。

暫無
暫無

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

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