first post here. I am supposed to build a BST (which I have done) and create a deleteNode function. I keep trying to run the function but it is unfortunately not working.
#deleteFunction#
def deleteNode(self, data):
if self is None: ##none is left and right val
return self
if data < self.data: #if input is less than current
self.left = self.deleteNode(self.left, data) #go to the left node
elif (data > self.data): #if input is higher, go to right node
self.right = self.deleteNode(self.right, data)
else:
if self.left is None:
temp = self.right #if left is none then assign temp to right
self.left = None
return temp
elif self.right is None: #if right is none, assign temp to left
temp = self.left
self.left = None
return temp
temp = findMinNode(self.right) ##node with two children, get the smallest right subtree
self.data = temp.data ##copy the right small subtree
self.right = deleteNode(self.right, temp.data) #delete smallest right subtree
return self
##Execution code:##
print("Maximum node in BT: \n", dTree.findMaxNode())
print("Minimum node in BT: \n",dTree.findMinNode())
print("Post Order: \n", dTree.postOrderTrav())
print("Pre Order: \n", dTree.preOrderTrav())
print("In Order: \n", dTree.inOrderTrav())
dTree.deleteNode(4)
print("deletion of one node: ")
print (dTree.inOrderTrav())
I keep receiving the following error:
line 262, in <module> dTree.deleteNode(4)
File "C:/Users", line 215, in deleteNode self.right = self.deleteNode(self.right, data)
TypeError: deleteNode() takes 2 positional arguments but 3 were given
200
This is my favorite version of deleting a node in BST - use deleteNode function, with root being the root node and key being the node value that you want to delete.
class DeletingNodeBST:
def successor(self, root):
root = root.right
while root.left:
root = root.left
return root.val
def predecessor(self, root):
root = root.left
while root.right:
root = root.right
return root.val
def deleteNode(self, root, key):
if not root:
return None
if key > root.val:
root.right = self.deleteNode(root.right, key)
elif key < root.val:
root.left = self.deleteNode(root.left, key)
else:
if not (root.left or root.right):
root = None
elif root.right:
root.val = self.successor(root)
root.right = self.deleteNode(root.right, root.val)
else:
root.val = self.predecessor(root)
root.left = self.deleteNode(root.left, root.val)
return root
Note that root is the root node, which can be created with:
class Node:
def __init__(self, key):
self.key = key
self.left = None
self.right = None
Related
I currently have my code set up so I have a class that creates the first node of a binary search tree. Then, using a create_node method, I can add whatever node. How can I return the children of each created note?
When I run the following, I get an output of "Left child: None Right Child: None" when it should be "Left child: 3 Right Child: 7"
I'd assume it has something to do with the dictionary not being updated? If this is the case, how can I continually update it? Thank you!
totaldict = {}
class TreeNode:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def search(self, value):
if value < self.data:
if self.left == None:
return False
else:
return self.left.search(value)
elif value > self.data:
if self.right == None:
return False
else:
return self.right.search(value)
else:
return True
def create_node(self, value):
if value < self.data:
if self.left == None:
self.left = TreeNode(value)
totaldict[value] = TreeNode(value)
else:
return self.left.create_node(value)
elif value > self.data:
if self.right == None:
self.right = TreeNode(value)
totaldict[value] = TreeNode(value)
else:
return self.right.create_node(value)
else:
print("Node already exists")
def pos_child(self, value):
if self.search(value):
if value in totaldict:
return "Left child: " + str(totaldict[value].left) + " Right Child: " + str(totaldict[value].right)
else:
print("Node does not exist, use create_node method")
root = TreeNode(10)
root.create_node(5)
root.create_node(15)
root.create_node(3)
root.create_node(7)
print(root.pos_child(5))
The problem is here:
if self.right == None:
self.right = TreeNode(value)
totaldict[value] = TreeNode(value) # HERE
You create new TreeNode but it's not connected at all to root so it never gets any children. Change it to:
if self.right == None:
self.right = TreeNode(value)
totaldict[value] = self.right
And do the same for left subtree.
How can I find the minimum node in this binary search tree. I can't make it work.
....................................................................
....................................................................
class BinarySearchTree:
def __init__(self, root):
self.root = root
self.left = None
self.right = None
def insert(self, node):
if node == self.root:
return
elif node < self.root:
if self.left:
self.left.insert(node)
else:
self.left = BinarySearchTree(node)
else:
if self.right:
self.right.insert(node)
else:
self.right = BinarySearchTree(node)
def search(self, target):
if target == self.root:
return True
else:
if target < self.root:
if self.left:
return self.left.search(target)
return False
if target > self.root:
if self.right:
return self.right.search(target)
return False
def find_min(self, root):
# traverse left subtree
while root is not None:
root = self.left
return root
def find_min(self):
# traverse left subtree
current = self
while self.left is not None:
current = self.left
return current.root
tree = BinarySearchTree("10")
tree.insert("20")
tree.insert("30")
print(tree.search("20")) # output: True
print(tree.search("40")) # output: False
print(tree.find_min()) # output: 10
I am implementing a BST and everything works, even the deletion with two children.The only bug is in the deletion of a leaf which seems such a trivial task.
There seem to be still a reference to the leaf node but I can’t get on top of this issue.Putting node = None doesn’t remove the entire Node.I have also tried del node
without any luck.If you could spot the problem it would be nice.
import random
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
self.parent = None
self.left_child = None
self.right_child = None
self.level = None
class Tree:
def __init__(self):
self.root = None
self.size = 0
self.height = 0
def _insertion(self, root, data):
new_node = Node(data)
if root.data < data:
if root.right:
return self._insertion(root.right, data)
root.right = new_node
root.right.parent = root
root.right_child = root.right
return
if root.data > data:
if root.left:
return self._insertion(root.left, data)
root.left = new_node
root.left.parent = root
root.left_child = root.left
return
def insertion(self, data):
new_node = Node(data)
if not self.root:
self.root = new_node
return
return self._insertion(self.root, data)
def _get_height(self, root):
if not root:
return -1
left_height = self._get_height(root.left)
right_height = self._get_height(root.right)
return 1 + max(left_height, right_height)
def get_height(self):
if not self.root:
return 0
return self._get_height(self.root)
def fill_random(self, num_nodes):
for i in range(num_nodes):
random_num = int(random.random()*100)
self.insertion(random_num)
def _inorder(self, root):
if root:
self._inorder(root.left)
print(root.data)
self._inorder(root.right)
def inorder(self):
root = self.root
return self._inorder(root)
def get_max(self, node):
while node.right:
node = node.right
return node.data
def search(self, data):
root = self.root
while root.right or root.left:
if root.data < data:
root = root.right
if root.data > data:
root = root.right
if root.data == data:
return root
return None
def _delete_node(self, root, data):
if root:
if root.data < data:
return self._delete_node(root.right, data)
if root.data > data:
return self._delete_node(root.left, data)
if root.data == data:
if not root.left and not root.right:
root = None
return
if not root.left and root.right:
root = root.right
root.right = None
return
if not root.right and root.left:
root = root.left
root.left = None
return
if root.right and root.left:
value = self.get_max(root)
print(f"This is the value: {value}")
root.data = value
self._delete_node(root.right, value)
def delete_node(self, data):
if not self.root:
return None
return self._delete_node(self.root, data)
if __name__ == '__main__':
my_tree = Tree()
my_tree.insertion(33)
my_tree.insertion(36)
my_tree.insertion(25)
my_tree.insertion(20)
my_tree.insertion(27)
my_tree.insertion(35)
my_tree.insertion(39)
my_tree.delete_node(33)
my_tree.inorder()
my_tree.search(35)
In your _delete_node function, it doesn't help to set root to None. That only affects the variable, but does not bring any change to the tree.
A common "trick" is to return root to the caller -- who is then responsible to assign that returned value back to where it is referenced in the tree. For instance, if the recursive call was made with root.left as argument, and the recursive call wants to delete that node, it will return None, and the caller must then assign (whatever it gets back) to root.left. So now the tree is mutated as intended.
Here are your delete_node functions adapted along that principle:
def _delete_node(self, root, data):
if root:
if root.data < data:
root.right = self._delete_node(root.right, data)
elif root.data > data:
root.left = self._delete_node(root.left, data)
elif not root.left:
return root.right
elif not root.right:
return root.left
else:
value = self.get_max(root)
print(f"This is the value: {value}")
root.data = value
root.right = self._delete_node(root.right, value)
return root
def delete_node(self, data):
if self.root:
self.root = self._delete_node(self.root, data)
Another remark
Your search function has some issues:
The while condition should check whether root is None before accessing any of its attributes.
The if blocks should be tied together with elif, otherwise the execution may fall into a second if block which is not the intension.
Here is the corrected version:
def search(self, data):
root = self.root
while root:
if root.data < data:
root = root.right
elif root.data > data:
root = root.left
else:
return root
return None
Little improvement
To help debug this code, I altered the inorder method with a little change, so that the tree is printed with indentations:
def _inorder(self, root, indent=""):
if root:
self._inorder(root.left, indent+" ")
print(indent + str(root.data))
self._inorder(root.right, indent+" ")
This helps to quickly see the structure of the tree. You might even want to switch left and right, so that it looks like a rotated tree.
This block of code doesn't do anything:
if root.data == data:
if not root.left and not root.right:
root = None
return
because root is a local variable; reassigning it to None doesn't affect the tree.
What you need to do is change the parent node's right or left pointer. I'd suggest doing this before you recurse, but you could also solve it by passing the parent node into this function.
By making a node to be deleted from the tree, the node (case 1) can be a node with a single arm (right or left), or a node with both branches. In case the node to be deleted is an intermediate node with two branches, there are 2 different methods.
Method 1: the largest knot on the left arm or the smallest knot on the right arm, and
Method 2: The node in the branch with more depth (or the number of elements) is fulfilled so that the right or left arm is balanced.
Both methods have to be coded with separate functions.
How can I do these two methods?
class Node:
def __init__(self, data):
self.left = None
self.right = None
self.parent = None # new
self.data = data
def insert(self, data):
if self.data: # add by comparison
if data < self.data: # left if small
if self.left is None: # add left if left is blank
self.left = Node(data)
self.left.parent = self # new
else:
self.left.insert(data) # if left is not empty add to left sub-tree
elif data > self.data: # right if greater
if self.right is None: # add right if right is blank
self.right = Node(data)
self.right.parent = self # new
else: # if right is not empty add to sub-tree right
self.right.insert(data)
else:
self.data = data # the first dream of the tree
# print Tree
def PrintTree(self):
print( self.data,end='-')
if self.left:
self.left.PrintTree()
if self.right:
self.right.PrintTree()
def sizeTree(self):
if self.left and self.right:
return 1 + self.left.sizeTree() + self.right.sizeTree()
elif self.left:
return 1 + self.left.sizeTree()
elif self.right:
return 1 + self.right.sizeTree()
else:
return 1
def depth(self):
if self.left and self.right:
l = self.left.depth()
r = self.right.depth()
return 1 + max(l,r)
elif self.left:
return 1 + self.left.depth()
elif self.right:
return 1 + self.right.depth()
else:
return 1
# Use the insert method to add nodes
root = Node(25)
root.insert(12)
root.insert(10)
root.insert(22)
root.insert(5)
root.insert(36)
root.insert(30)
root.insert(40)
root.insert(28)
root.insert(38)
root.insert(48)
root.PrintTree()
"""
# 25,36,20,10,5,22,40,48,38,30,22,12,28
root = Node(25)
root.insert(36)
root.insert(20)
root.insert(10)
root.insert(5)
root.insert(22)
root.insert(40)
root.insert(48)
root.insert(38)
root.insert(30)
root.insert(12)
root.insert(28)
print("\n",root.sizeTree(),root.depth())
"""
Some time ago I was playing with this and came up with this code:
def search(self, value):
"""
Recursively looks to the left and right of Tree depending on the provided value
and returns it if it is present within Tree.
Args:
value (int): value to be searched for within Tree
Returns:
value if value exists in Tree otherwise None
"""
if value < self.data:
if self.left is None:
return None
return self.left.search(value)
elif value > self.data:
if self.right is None:
return None
return self.right.search(value)
else:
return self.data
def _findNodeToDelete(self, value, previous=None):
"""
Recursively looks to the left and right of Tree depending on the provided value
and returns it if it is present within Tree.
Args:
value (int): value to be searched for within Tree
Returns:
value if value exists in Tree otherwise None
"""
if value < self.data:
if self.left is None:
return None
return self.left._findNodeToDelete(value, self)
elif value > self.data:
if self.right is None:
return None
return self.right._findNodeToDelete(value, self)
else:
return self, previous
def _mergeNodes(self, target):
self.data = target.data
self.left = target.left
self.right = target.right
def deleteNode(self, value, start=None):
if self.search(value):
to_delete, parent = self._findNodeToDelete(value, start)
if to_delete.right and to_delete.left:
new_value = to_delete.right.min
to_delete.data = new_value
to_delete.right.deleteNode(new_value, to_delete)
elif to_delete.left:
to_delete._mergeNodes(to_delete.left)
elif to_delete.right:
to_delete._mergeNodes(to_delete.right)
else:
if parent:
if parent.data > value:
parent.left = None
else:
parent.right = None
else:
self.data = None
Note, I don't use parent attribute, rather calculate it while deleting.
The logic I tried:
def min_tree_value(self):
while self.left:
self.left = self.left.left
return self.data
Actual Python program Logic:
def min_tree_value(self):
if self.left is None:
return self.data
return self.left.min_tree_value()
The actual Python program logic is in recursion form. I tried the same logic in While loop()
I'm not sure whether my logic is correct. Do help me to figure out the incorrect logic and point where I'm Wrong.
Your logic is almost there, but not quite:
def min_tree_value(self):
node = self
while node.left:
# don't change the structure by rebinding node.left,
# but iterate the tree by moving along nodes!
node = node.left
return node.data
Note that in the original code, you never reassign self before returning its value, so you always returned the root value.
First of all, the question asks about finding the minimum element in a binary tree.
The algorithm you used, will find the minimum element in the Binary Search Tree (as the leftmost element is the minimum).
For finding minimum element in a simple Binary Tree, use the following algorithm:
# Returns the min value in a binary tree
def find_min_in_BT(root):
if root is None:
return float('inf')
res = root.data
lres = find_min_in_BT(root.leftChild)
rres = find_min_in_BT(root.rightChild)
if lres < res:
res = lres
if rres < res:
res = rres
return res
Additions to the answer after OP changed the question:
The logic for the algorithm you tried is correct, with a small correction in the implementation: self = self.data. Both of them find the leftmost element.
I have also tested both the functions which return the same output:
class Node:
def __init__(self, data):
self.left = None
self.right = None
self.data = data
def insert(self, data):
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
def findval(self, lkpval):
if lkpval < self.data:
if self.left is None:
return str(lkpval)+" Not Found"
return self.left.findval(lkpval)
elif lkpval > self.data:
if self.right is None:
return str(lkpval)+" Not Found"
return self.right.findval(lkpval)
else:
print(str(self.data) + ' is found')
def PrintTree(self):
if self.left:
self.left.PrintTree()
print( self.data),
if self.right:
self.right.PrintTree()
def min_tree_value_original(self):
if self.left is None:
return self.data
return self.left.min_tree_value_original()
def min_tree_value_custom(self):
while self.left:
self = self.left
return self.data
root = Node(12)
root.insert(6)
root.insert(14)
root.insert(3)
root.insert(3)
root.insert(1)
root.insert(0)
root.insert(-1)
root.insert(-2)
print(root.min_tree_value_original())
print(root.min_tree_value_custom())
Output:
-2
-2
Here -2 is the smallest and the leftmost element in the BST.