问题
I wish to delete the leftmost leaf in a BT( not BST!). I tried to delete it using Reverse level order traversal but once I find the leftmost node and delete it and try returning, I cannot handle the extra recursive calls. Basically with the current code, my entire tree gets deleted recursively, but I just want it to delete leftmost leaf.
I tried breaking the recursion using exit() and my entire program stopped.
On first call only 5 should be deleted. On next call 25 should be deleted . On next call 66 should be deleted.( basically swimming up)
This is what my code looks like:
def del_leaf(node):
if(root==None):
return
if root:
# First recur on left child
del_leaf(root.left)
# the recur on right child
del_leaf(root.right)
# now print the data of node
if ( (root.isvisited == False)):
root.isvisited = True
root.left = None
root.right = None
return
回答1:
The function needs a return value, something that tells the caller:
- this node does not exist
- this node is childless so you can delete it
- OK, we're done.
So, something like
def del_leaf(node):
if(root==None):
return 1
left = del_leaf(root.left)
if (left == 2):
root.left = None
return 3
if (left == 3):
return 3
right = del_leaf(root.right)
if (right == 2):
root.right = None
return 3
if (right == 3):
return 3
return 2
I haven't tested it; that's left as an exercise for you. Also left:
- better enum names than 1, 2, and 3
- support for an arbitrary number of child nodes
- support for an ordering function
回答2:
I have modified the program that does not use recursion to:
- Not rely on garbage collection to print out when a node has been removed.
- Build the entire tree as presented by the OP.
Note: When the program descends down the left subtree and finds that the leftmost leaf has a right subtree, it removes this subtree. This program does not descend down the right subtree to delete the leftmost leaf of that subtree. The second algorthm does. Take your pick.
class Node:
def __init__(self, value):
self.value = value
# build tree
root = Node(90)
# left subtree:
node_50 = Node(50)
node_20 = Node(20)
node_75 = Node(75)
node_5 = Node(5)
node_5.left = None
node_5.right = None
node_25 = Node(25)
node_25.left = None
node_25.right = None
node_66 = Node(66)
node_66.left = None
node_66.right = None
node_80 = Node(80)
node_80.left = None
node_80.right = None
root.left = node_50
node_50.left = node_20
node_50.right = node_75
node_20.left = node_5
node_20.right = node_25
node_75.left = node_66
node_75.right = node_80
# right subtree:
node_150 = Node(150)
node_95 = Node(95)
node_175 = Node(175)
node_92 = Node(92)
node_92.left = None
node_92.right = None
node_111 = Node(111)
node_111.left = None
node_111.right = None
node_166 = Node(166)
node_166.left = None
node_166.right = None
node_200 = Node(200)
node_200.left = None
node_200.right = None
root.right = node_150
node_150.left = node_95
node_150.right = node_175
node_95.left = node_92
node_95.right = node_111
node_175.left = node_166
node_175.right = node_200
def del_leftmost_leaf(root):
if root.left is None and root.right is None:
print(f'Removing {root.value}')
return None # root has changed to None
parent = root
if root.left is None:
node = root.right
else:
node = root.left
while node.left:
parent = node
node = node.left
if node.right is None:
print(f'Removing {node.value}')
if parent.left is None:
parent.right = None
else:
parent.left = None
else:
print(f'Removing {node.right.value}')
node.right = None
return root # root hasn't changed
while root:
root = del_leftmost_leaf(root)
Prints:
Removing 5
Removing 25
Removing 20
Removing 75
Removing 50
Removing 92
Removing 111
Removing 95
Removing 175
Removing 150
Removing 90
See demo
Second Algortihm
def del_leftmost_leaf(root):
if root.left is None and root.right is None:
print(f'Removing {root.value}')
return None # root has changed to None
parent = root
if root.left is None:
node = root.right
else:
node = root.left
while node.left:
parent = node
node = node.left
if node.right is None:
print(f'Removing {node.value}')
if parent.left is None:
parent.right = None
else:
parent.left = None
else:
node.right = del_leftmost_leaf(node.right)
return root # root hasn't changed
while root:
root = del_leftmost_leaf(root)
Prints:
Removing 5
Removing 25
Removing 20
Removing 66
Removing 80
Removing 75
Removing 50
Removing 92
Removing 111
Removing 95
Removing 166
Removing 200
Removing 175
Removing 150
Removing 90
See demo
回答3:
If you only actually to remove the leftmost leaf node, a simple recursion can handle this problem pretty easily, but you'll need to use a return value from the function to communicate information back up the call stack. I suggest we return True if the current node is the leaf we're searching for, which should be deleted by its parent, and False otherwise:
def del_leaf(node):
if node is None:
raise ValueError("Can't remove a leaf node from an empty tree")
if node.left: # first recursive case
if del_leaf(node.left): # if the recursion returns True, our immediate child is a leaf
node.left = None # so delete it
return False
elif node.right: # second recursive case
if del_leaf(node.right):
node.right = None
return False
else: # base case, we're the leaf!
return True
Note that a function like this cannot ever delete the root value of a one-element tree, because it don't own the reference to that root node (that's probably in a variable in the calling scope). What it will do is return True to the caller in that case, so the calling code can delete the root reference itself, if necessary.
However, if you're really looking to remove the furthest leaf node from the root, with a preference for the leftmost if there are several leaves at the same depth, then you need a somewhat more sophisticated algorithm.
One way to do it that might be pretty efficient is to make sure each node keeps its height as an attribute. Then we can easily tell which branch of the tree we need to follow to find the leaf we want to remove.
# assume the nodes have a height attribute, leaf nodes have height 0
def update_height(node): # a helper function
node.height = 1 + max(node.left.height if node.left is not None else -1,
node.right.height if node.right is not None else -1)
# use this to initially set up heights (if you don't build them into the tree structure)
def setup_heights(node):
if node is None:
return
setup_heights(node.left)
setup_heights(node.right)
update_height(node)
def del_leaf(node):
if node is None:
raise ValueError("Can't remove from an empty tree")
if node.height == 0:
return True # the root needs to be removed by the caller
if self.height == 1: # we're the parent of a leaf, so delete one of our child nodes
if self.left is not None:
self.left = None
else:
self.right = None
elif self.left is not None and (self.right is None or
self.left.height >= self.right.height):
del_leaf(self.left)
else:
del_leaf(self.right)
update_height(node)
return False
来源:https://stackoverflow.com/questions/58572946/deleting-leftmost-leaf-in-a-binary-tree