Delete a node from the binary tree with python - python

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.

Related

How do I return the children of recursive nodes in a python binary tree?

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.

Binary Search Tree Find minimum not clear

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.

Delete a segment from BST in Python

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

List of all elements of Binary Tree

Being a beginner, I have been trying to implement Binary Tree in python. And have been available to implement a lot successfully with only one problem that I am unable to return a list of all the elements (traverse())in the binary tree. I am using two classes here, Node and BinaryTree.
Node Class
class Node:
def __init__(self, val):
self.value = val
self.left = None
self.right = None
Traverse method to return all the elements in the binary tree.
def traverse(self): #<-- Problem here
tree_elements = []
if self.left != None:
self.left.traverse()
tree_elements.append(self.value)
#debug
print(self.value, end=" ")
if self.right != None:
self.right.traverse()
return tree_elements
def addNode(self, node):
if node.value < self.value and node.value != self.value:
if self.left == None:
self.left = node
else:
self.left.addNode(node)
elif node.value > self.value and node.value != self.value:
if self.right == None:
self.right = node
else:
self.right.addNode(node)
def search(self, val):
if val == self.value:
return "Found"
elif val < self.value:
if self.left != None:
return self.left.search(val)
else:
return "Not Found "
elif val > self.value:
if self.right != None:
return self.right.search(val)
else:
return "Not Found"
Binary Tree
class BinaryTree:
def __init__(self):
self.root = None
def addVlaue(self, val):
node = Node(val)
if self.root == None:
self.root = node
else:
self.root.addNode(node)
def search(self, val):
if self.root == None:
return False
else:
return self.root.search(val)
def traverse(self):
if self.root == None:
return "no data"
else:
return self.root.traverse()
Problem:
traverse method has to return all the elements in the binary tree, but i have been getting only first value of the tree.
example:
elements: 100 18 46 5 65 5 31 71 94 43 #input in the tree
output from tree:
5 18 31 43 46 65 71 94 100 #expected output
[100] #output from the tree
The tree_elements list needs to go along the recurvise calls, collecting each node along the way. In other words, it must be passed as an argument to traverse calls (except when calling traverse for the root node).
Otherwise a new list is created and discarded in each traverse call (since you never do anything with the return value of traverse during its recursion), except for the top recursive call which returns the root element only.
Try this implementation:
def traverse(self, tree_elements=None):
if tree_elements is None:
tree_elements = []
if self.left != None:
self.left.traverse(tree_elements=tree_elements)
tree_elements.append(self.value)
if self.right != None:
self.right.traverse(tree_elements=tree_elements)
return tree_elements

cannot see syntax error

I'm trying to build a binary search tree library and I'm getting a syntax error on my piece of code:
class Node:
"""
Tree node: Left and Right child + data which can be any object
"""
def __init__(self,data):
"""
Node constructor
"""
self.left = None
self.right = None
self.data = data
def insert(self,data): # self --> object self.data
"""
Insert new node with data
"""
if data < self.data: # insert data less than current root
if self.left is None: # if left node is empty,
self.left = Node(data) # object left --> Node with new data
else:
self.left.insert(data) # if left node is not empty, go insert again
else:
if self.right is None: # insert data greater than current node
self.right = Node(data) # object right --> Node with new data
else:
self.right.insert(data) # if not empty, run insert again
def lookup(self, data, parent = None):
"""
Lookup node containing data
"""
if data < self.data:
if self.left is None:
return None, None
return self.left.lookup(data,self)
elif data > self.data:
if self.right is None:
return None, None
return self.right.lookup(data,self)
else:
return self, parent
def delete(self, data):
"""
delete node containing data
"""
""" no child """
if children_count == 0:
# if node has no children, remove it
if parent.left is node: # if parent is pointing to current node
parent.left = None # set parent pointing left to None
else:
parent.right = None # else set parent pointing right to None
del node # del node
""" 1 child """
elif children_count == 1:
# if node has 1 child
# replace node by it's child
if node.left:
n = node.left
else:
n = node.right
if parent:
if parent.left is node:
parent.left = n
else:
parent.right = n
del node
""" 2 children """
else:
# if node has 2 children
# find its successor
parent = node # parent is equal to current node target of deletion
successor = node.right # successor is right of the node
while successor.left:
parent = successor
successor = successor.left
# replace node data by its successor data
node.data = successor.data
#fix successor's parent's child
if parent.left == successor:
parent.left = successor.right
else:
parent.right = successor.right
def children_count(self):
""" Return the number of children """
if node is None:
return None
cnt = 0
if self.left:
cnt += 1
if self.right:
cnt += 1
return cnt
# method to print tree in order. Use recursion inside print_tree() to walk the tree breath-first
def print_tree(self):
if self.left:
self.left.print_tree()
print self.data,
if self.right:
self.right.print_tree()
the error is:
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
import BSTlib
File "BSTlib.py", line 78
elif children_count == 1:
^
I can't seem to see what is wrong =[ Can someone help me point this out? Thank you!
This is an error with the docstring and whitespace. Run this code:
if False:
print 'hi'
"""1 child"""
elif True:
print 'sdf'
And you get a similar SyntaxError.
Remove the docstring (or just move it) and remove the extra whitespace:
if False:
print 'hi'
elif True:
print 'sdf'
If you need to comment, then just use the hash #:
if False:
print 'hi'
# 1 child
elif True:
print 'sdf'

Categories

Resources