Deleting leftmost leaf in a binary tree - python

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

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

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

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

Related

Deletion in BST (python) | unexpected additional deletions?

def delete(node, key):
if not node: return None
# Wrong node, search correct child
if key < node.data:
delete(node.left, key)
elif key > node.data:
delete(node.right, key)
# Correct node found
else:
#1. node has no children
if not (node.left and node.right): return None
#2. node has only left child
if node.left and not node.right: return node.left
#3. node has only right child
if not node.left and node.right: return node.right
#4. node has both left & right children
## Need to replace current value with next biggest value
## So go right once then all left to end
## Once this value is found, assign to appropriate position
## Then remove this val from its previous position
temp = node.right
while temp.left: temp = temp.left
node.data = temp.data
node.right = delete(node.right, temp.data)
t = BinaryTree([100, 50, 200, 25, 75, 350])
delete(t.root, 100)
I think that this BST deletion code mostly works, but it's a little buggy. If I delete the root node, 100, then 350 will be missing, following, given the BST, t = BinaryTree([100, 50, 200, 25, 75, 350]).
What is going on here? I'm not sure why 350 has been deleted in the process. I'm wondering if it's related to how I replace the node value upon successful deletion.
Optional but possibly helpful context
class BinaryTreeNode:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
class BinaryTree:
def __init__(self, *args):
if len(args) < 1:
self.root = None
elif isinstance(args[0], int):
self.root = BinaryTreeNode(args[0])
else:
self.root = None
for x in args[0]:
self.insert(x)
def insert(self, node_data):
new_node = BinaryTreeNode(node_data)
if not self.root:
self.root = new_node
else:
# root has no parent, so assign none for 1st iteration
parent = None
temp_pointer = self.root
while temp_pointer:
# update parent
parent = temp_pointer
#update temp_pointer to left or right child
if node_data <= temp_pointer.data:
temp_pointer = temp_pointer.left
else:
temp_pointer = temp_pointer.right
# eventually, temp_pointer will point to None, exiting while loop
# assign to left or right child as appropriate
if node_data <= parent.data:
parent.left = new_node
else:
parent.right = new_node
There are a few issues:
As delete is designed to return a node reference or None, you should make sure not to ignore that returned reference. You did it right near the end of your function (node.right = delete(node.right, temp.data)), but elsewhere delete is called without regards of the returned reference. So:
The initial call in the main program should look like this:
t.root = delete(t.root, 100)
This will ensure that the root attribute is set to None when the last node has been deleted from the tree.
The recursive call in the first if block should be:
node.left = delete(node.left, key)
And similarly in the second block:
node.right = delete(node.right, key)
The function delete should always return a node reference after a recursive call has been made, yet this is missing in many of your cases, so add at the very bottom of your function a kind of "catch all" and return the current reference you have:
return node
The condition for identifying a leaf node is wrong. The and should be a or:
if not (node.left or node.right): return None
The corrected code -- comments indicate changes:
def delete(node, key):
if not node: return None
if key < node.data:
node.left = delete(node.left, key) # assign back!
elif key > node.data:
node.right = delete(node.right, key) # assign back!
else:
if not (node.left or node.right): return None # condition corrected
if node.left and not node.right: return node.left
if not node.left and node.right: return node.right
temp = node.right
while temp.left: temp = temp.left
node.data = temp.data
node.right = delete(node.right, temp.data)
return node # always return a node when a recursive call was made
t = BinaryTree([100, 50, 200, 150, 175, 25, 75, 350])
t.root = delete(t.root, 350) # assign back!
Considerations
Not a problem in the algorithm, but it is a good habit to put the body of an if or while statement on the next line, indented
This function would better be a method on the BinaryTree class -- then the main program should not have to worry about getting/setting the root attribute -- and most of the function's (recursive) logic could be implemented as a method on the BinaryTreeNode class.

Covert Binary Tree to Doubly Linked List (Microsoft Interview)

We are converting a binary tree into a DLL, in place also we are using in order traversalto do so.
Read more here - Link
My Code:
class BinaryTree():
def __init__(self,data):
self.data = data
self.left = None
self.right = None
def btToDll(node,head):
prev = None
return getbtToDll(node,head,prev)
def getbtToDll(node,head,prev):
if node is None:
return
getbtToDll(node.left,head,prev)
if prev is None:
head = node
else:
node.left = prev
prev.right = node
prev = node
getbtToDll(node.right,head,prev)
def printList(head):
if head is None:
print("NO LL FOUND AT THIS NODE")
else:
temp = head
while(temp):
print(temp.data)
temp = temp.right
root = BinaryTree(10)
root.left = BinaryTree(12)
root.right = BinaryTree(15)
root.left.left = BinaryTree(25)
root.left.right = BinaryTree(30)
root.right.left = BinaryTree(36)
head = None
head1 = btToDll(root,head)
printList(head1)
My problem:
The head is always None and hence I cannot print the converted list. What is wrong with this code or my logic?
Your code has many Pitfalls, the main reason why it return none is because from btToDll returns nothing, also it doesn't change the value of head, which it still None.
Instead of trying to repair your code, I preferred to go in a different Approach all in once.
Basically, I found a trick to get the result:
Go down to the most left Node which becomes the HEAD.
Check if from the Head You can go Up one, then left- left. or Up One right right and so on. If you can go Left then set the current node as the left bottom node. Do this untill there isn't any Node. Add the Previous node in the DLL list
Caluclate the current node, its previous and the Right node from the Previoys.
Go back from the Binary Tree, one reach the Root node (10), repeat the same pattern.
You will see that basically, if in any given Sub-node, there is a left node, then you calculate the entire Triangle, the most important node is always the left and becomes the current node. If left node is not present, then the Parent node becomes the current node, then you need to check whether the parent has a right node not.
I prepared some pictures, is much better to visualize this than explain it.
Take this Binary Tree:
First Step | Go To the most far left node as possible
Second Step | Calculate the First Triange
Note: If the Right bottom Node (30) HAS a left child node, then 30 won't be added, which is the case of this example, instead it goes to the next step.
Step 3 | Go to the next Triangle step of the Child's child node##
Step 4 | Now go up to the root node and calculate the left side of BT
Note: See the complete path of this algorithm, again I imagine that as many small triangles that are calculated Separately.
Source Code
NOTE: Is been lengthy, but I did it on the fly, can be improved.
class BinaryTree():
def __init__(self, data):
self.data = data
self.left = None
self.right = None
self.prev = None
self.visited = False
def create_tree(self, show_tree=False):
"""Creating the Tree with a Depth-First Search Algorithm"""
root = self # Set Current Node
stack = [root]
while True:
if not stack:
break
current = stack.pop() # Remove Current From Stack
if current.right:
current.right.prev = current
stack.append(current.right)
if current.left:
current.left.prev = current
stack.append(current.left)
if show_tree:
print(f'{current.data} --> ', end='')
def create_dll(root_head):
"""Algorithm to Conver Binary Tree to Doubly Linked List"""
doubly_linked_list = []
# --- Find DLL Head NOTE: Just need to go left from Binary Tree till hit NONE
head = None
current = root_head
while True:
if current.left:
current = current.left
else:
head = current
break
stack = [head]
visited = set()
def add_node(*args, add_dll=None):
"""Helper Function, Add Node to the Visited Set."""
for item in args:
visited.add(item)
if add_dll:
for node in add_dll:
doubly_linked_list.append(node)
# --- Crawls back up, following each Triangle Shape from left Vertices to Right
while True:
try:
current = stack.pop()
except IndexError:
pass
if current in doubly_linked_list:
break
if current.left and current.left not in visited: # NOTE: Goes Down to Next Triangle Shape
stack.append(current.left)
continue
elif current.prev: # NOTE: Goes Up one Node
add_node(add_dll=[current])
# --------------- Check if we can go to the left.
if current.prev.right.left and current.prev.right.left not in visited: # NOTE: Goes deeper
add_node(current.prev, current.prev.right, add_dll=[current.prev])
if current.prev.prev: # NOTE: Backtracking
stack.append(current.prev.prev)
stack.append(current.prev.right.left)
continue
# ------------- Here We Handle in case previous Node Has ONLY Right path
elif current.prev.right.right:
if current.prev.right.right.left: # If has Left Node we go deeper
stack.append(current.right.right.left)
continue
add_node(add_dll=[current.prev.right.right])
else:
add_node(current.prev, add_dll=[current.prev])
if current.prev.right: # DOES the Prev node have a Right node?
add_node(current.prev.right, add_dll=[current.prev.right])
if current.prev.prev and current.prev.prev not in visited: # NOTE: BackTrackin
stack.append(current.prev.prev)
# -------------- >N OTE: Here Handle The 'Root node' (i.e. 10), only option is to go to right
elif current.right:
add_node(current, add_dll=[current])
if current.right.left: # Going Deeper
stack.append(current.right.left)
continue
elif current.right.right:
if current.right.right.left:
stack.append(current.right.right.left)
continue
add_node(current.right, current.right.right, add_dll=[current.right, current.right.right])
else:
add_node(current.right, add_dll=[current.right])
return doubly_linked_list
def show_ddl(ddl):
"""Helper function, used to print the Doubly Linked List"""
for node in ddl:
print(f'{node.data} --> ', end='')
# ---------> Creating The Binary Tree >
root = BinaryTree(10)
root.left = BinaryTree(12)
root.right = BinaryTree(15)
root.left.left = BinaryTree(25)
root.left.right = BinaryTree(30)
root.left.right.left = BinaryTree(60)
root.left.right.right = BinaryTree(77)
root.right.right = BinaryTree(40)
root.right.left = BinaryTree(36)
root.right.left.left = BinaryTree(50)
root.right.left.right = BinaryTree(13)
print('\nBynary Tree:\n')
root.create_tree(show_tree=True)
print()
print('==='*15)
print()
# ---------> Creating The Doubly Linked List >
print('Doubly Linked List:\n')
dll = create_dll(root)
show_ddl(dll)
Output
Bynary Tree:
10 --> 12 --> 25 --> 30 --> 60 --> 77 --> 15 --> 36 --> 50 --> 13 --> 40 -->
=============================================
Doubly Linked List:
25 --> 12 --> 60 --> 30 --> 77 --> 10 --> 50 --> 36 --> 13 --> 15 --> 40 -->

Can't understand this Binary Search Tree (BST) algorithm for Insertion of value in Python

I am learning algorithms. For the BST Construction to insert a value in the BST, I came across this code. I am not that good at OOPS concept and can't figure out how currentnode.left = BST(value) and currentnode = currentnode.left works. If someone can help me understand this, it would be of great help.
class BST:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def insert(self, value):
currentnode = self
while True:
if value < currentnode.value:
if currentnode.left is None:
currentnode.left = BST(value)
break
else:
currentnode = currentnode.left
else:
if currentnode.right is None:
currentnode.right = BST(value)
break
else:
currentnode = currentnode.right
return self
In the insert function, the currentnode has been assigned to self. Starting with the while loop, the parameter value is checked with currentnode's value. If it is small, the first condition is executed else second.
Now comes your doubt.
Let's say the first condition is being executed. If the currentnode's left value is none, then the code calls BST(value) i.e. the constructor is called which initiates a new node, which in turn becomes the currentnode's left child.
Else, if there is already a left child, that child becomes the currentnode and the while loop is iterated again and again until a suitable, position is found.
Also, If this code seems complicated. You should refer this, just in case if it helps.
class Node:
def __init__(self,key):
self.left = None
self.right = None
self.val = key
def insert(root,node):
if root is None:
root = node
else:
if root.val < node.val:
if root.right is None:
root.right = node
else:
insert(root.right, node)
else:
if root.left is None:
root.left = node
else:
insert(root.left, node)
# 5
# / \
# 3 7
# / \ / \
# 2 4 6 8
r = Node(5)
insert(r,Node(3))
insert(r,Node(2))
insert(r,Node(4))
insert(r,Node(7))
insert(r,Node(6))
insert(r,Node(8))

How to check if a Binary tree is full?

Student here. I have coded a method to add to a BinaryTree class that checks to see if the binary tree is full (the rest of the class code came from a Python textbook). I believe it is working as it should but am new to coding and I do not know how to check without the visual of the tree to see if all of the leaves are on the same level. Can anyone take a look at the is isFullBinaryTree(self) method is correct? It is near the end of the class. The test program seems to be working, but I am not positive.
My thought was that if I coded a count variable for each side of the tree and if the count is the same on both sides, then the leaves must all be on the same level which would make it a full tree.
Here is the full code:
class TreeNode:
def __init__(self, e):
self.element = e
self.left = None # Point to the left node, default None
self.right = None # Point to the right node, default None
class BinaryTree:
def __init__(self):
self.root = None
self.size = 0
# Insert element e into the binary search tree
# Return True if the element is inserted successfully
def insert(self, e):
if self.root == None:
self.root = self.createNewNode(e) # Create a new root/Create the node for e as the root
else:
# Locate the parent node
parent = None
current = self.root
while current != None:
if e < current.element:
parent = current # Keep the parent
current = current.left # Go left
elif e > current.element:
parent = current # Keep the parent
current = current.right # Go right
else:
return False # Duplicate node not inserted
# Create a new node for e and attach it to parent
if e < parent.element:
parent.left = self.createNewNode(e)
else:
parent.right = self.createNewNode(e)
self.size += 1 # Increase tree size
return True # Element inserted
# Create a new TreeNode for element e
def createNewNode(self, e):
return TreeNode(e)
# Returns true if the tree is a full binary tree
def isFullBinaryTree(self):
current = self.root # Start from the root
while current != None:
leftNode = current.left
rightNode = current.right
leftCount = 0
rightCount = 0
while leftNode != None:
current = leftNode
leftNode = current.left
leftCount += 1 # add 1 because we are moving from current one time
while rightNode != None:
current = rightNode
rightNode = current.right
rightCount += 1 # add 1 because we are moving from current one time
if leftCount == rightCount:
return True
else:
return False
return False
def main():
numbers = [2, 4, 3, 1, 8, 5, 6, 7, 0]
intTree1 = BinaryTree()
for e in numbers:
intTree1.insert(e)
print("\nIs intTree1 full? ", end = "")
print(intTree1.isFullBinaryTree())
numbers2 = [2, 4, 3, 1, 8, 5, 6, 7]
intTree2 = BinaryTree()
for e in numbers2:
intTree2.insert(e)
print("\nIs intTree2 full? ", end = "")
print(intTree2.isFullBinaryTree())
main()
If your tree looked like /\, then I think it would return True because you're only iterating the outside of the tree, not checking the fullness of the inner branches
Instead of looping at all, or even counting, I would suggest recursion
You'll need to implement the isFullBinaryTree methods on the TreeNode class for this to work, though.
class TreeNode:
def __init__(self, e):
self.element = e
self.left = None # Point to the left node, default None
self.right = None # Point to the right node, default None
def isFullBinaryTree(self):
# check if we are a leaf
if self.left is None and self.right is None:
return True
# recursively check the left fullness
full_left = self.left.isFullBinaryTree() if self.left else False
# recursively check the right fullness
full_right = self.right.isFullBinaryTree() if self.right else False
# return True if checked that both left and right are full
return full_left and full_right
Once you do this, then the BinaryTree class can simply be checking if the root exists and if the root TreeNode is considered full itself.
e.g.
def isFullBinaryTree(self):
return self.root.isFullBinaryTree() if self.root else False

Successor and Predecessor - Binary Search Tree (Python)

I am trying out this successor and predecessor on Binary search tree.
Just wondering once I get hold of successor code, can I flip it over and use it for predecessor?
I've coded the successor, and tried to use it for predecessor.
However, my output value doesn't change, even though I tried to place other value..
Below is my code:
Succ
def succ(self, key):
temp = self.root
prev = None
if (temp.right is not None):
temp = temp.right
while (temp.left is not None):
temp = temp.left
prev = temp
elif temp.left is not None:e
temp = temp.left
while (temp.right is not None):
temp = temp.right
prev = temp
else:
return None
return prev.key
Predecessor
def pred(self, key):
temp = self.root
prev = None
#if right is not none, succ lies in the right sub tree
if (temp.right is not None):
temp = temp.right
while (temp.left is not None):
#return the node with the minimum key value
temp = temp.left
prev = temp
#if left not none, succ lies in the right sub tree
elif temp.left is not None:
#go right till .right is None
#return the node with the maximum key value
temp = temp.left
while (temp.right is not None):
temp = temp.right
prev = temp
else:
#no succ
return None
return prev.key
the tree
def createTree(self):
#root
self.put("F",6)
#leftSubTree
self.put("D",4)
#leftLeftSubTree
self.put("C",3)
self.put("B",2)
self.put("A",1)
#LeftRightSubTree
self.put("E",5)
#RightSubTree
self.put("I",9)
#RightLeftSubTree
self.put("G",7)
self.put("H",8)
#RightRightSubTree
self.put("J",10)
To flip the succ function and turn it into pred, you need to change every left to a right, and every right to a left.
def pred(self, key):
temp = self.root
prev = None
if (temp.left is not None):
temp = temp.left
while (temp.right is not None):
temp = temp.right
prev = temp
elif temp.right is not None:
temp = temp.right
while (temp.left is not None):
temp = temp.left
prev = temp
else:
return None
return prev.key
Let us assume you have a BST node class with three pointers/references: left, right, and parent, which correspond to the left child, right child, and parent of a given node. The only node in the tree which has a parent that points to None would be the root node.
Let us also assume that we have the following BST:
15
/ \
9 20
/ \ / \
3 10 17 21
/ \ \
1 5 11
The BST property states that for any given node n, all nodes in n's left sub-tree shall be less than n; and, all nodes in n's right sub-tree shall be greater than n.
To make things easier when implementing the successor and predecessor functions, it is helpful to have auxiliary functions for finding the minimum and maximum node of a given BST or BST sub-tree.
Minimum
def bst_minimum(tree):
minimum = tree
while minimum is not None:
minimum = minimum.left
return minimum
Maximum
def bst_maximum(tree):
maximum = tree
while maximum is not None:
maximum = maximum.right
return maximum
For the tree example above, these functions would return 1 for the minimum and 21 for the maximum.
To find the predecessor of a given node, you have to cover a few cases:
If the given node has a left sub-tree, then take the maximum of that sub-tree.
Otherwise, move up the tree, following parent nodes until either you hit None or you "turn left."
In the second case, if you hit None, that means there is no predecessor. This would be the case for the node with value 1 in the tree above. It would following parent pointers all the way past the root node.
If there is a predecessor, then it will be the first parent node you encounter after making a left turn up the tree. Put another way, it is the parent node whose value is less than the value of the node from which you started. So, node 17 above would return the root node with a value of 15.
Predecessor
def bst_predecessor(tree):
if tree.left is not None:
return bst_maximum(tree.left)
parent = tree.parent
child = tree
while parent is not None and child is parent.left:
child = parent
parent = child.parent
return parent
Since the successor is simply the symmetrical operation to predecessor, you can modify predecessor by flipping the various operations. Namely:
Instead of checking the left sub-tree and finding the maximum, you want to check the right tree and find its minimum.
Otherwise, follow parent nodes until you can't anymore (in which case there is no successor), or you turn right. So, the successor of node 5, would be node 9 in the tree above.
Successor
def bst_successor(tree):
if tree.right is not None:
return bst_minimum(tree.right)
parent = tree.parent
child = tree
while parent is not None and child is parent.right:
child = parent
parent = child.parent
return parent

Categories