[英]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.left
和root.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.