I have a binary search tree. I have written basic insert, delete, traversal of the full tree and find its maximum and minimum node of the tree but I have trouble with finding maximum and minimum node after deleting the minimum or the maximum node.
This function deletes a specific node:
def deleteNode(self,val):
if self.data:
if self.data > val:
self.left.deleteNode(val)
elif self.data < val:
self.right.deleteNode(val)
else:
if self.left is None:
self.data = self.right
return True
elif self.right is None:
self.data = self.left
return True
else:
dltNode = self
dltNode.data = self.data
largest = self.left.findMax()
dltNode.data = largest
dltNode.left.deleteNode(largest)
return True
This function finds the minimum node:
def findMin(self):
if self.data:
if self.left is None:
return self.data
else:
return self.left.findMin()
And this is for the maximum node:
def findMax(self):
if self.data:
if self.right is None:
return self.data
else:
return self.right.findMax()
findMin and findMax functions work fine without deleting any node. If I ever call then after deleting the minimum and maximum node they will return None, whether they were supposed to return only integer node data. Here is the screenshot of my output:
It should print 34 instead of None.
Here is my full code
There are a few issues in deleteNode
if self.data
should not be there: this would mean you cannot delete a node with value 0 from the tree. A similar problem exists in other methods (findMin
, findMax
, insert
, ...).
self.left.deleteNode(val)
is executed without checking first that self.left
is not None
. The same is true for self.right.deleteNode(val)
self.data = self.right
assigns a Node reference to a data
attribute (which is supposed to be a number).
The function sometimes returns nothing (None
) or True
. Because of the recursive nature, the original caller of the method will get None
. This is not consistent.
The function cannot deal with deleting the root Node, as the caller will keep using the root node reference (t
or t2
in your example code).
To solve these issues, you should either create a separate Tree
class, or agree that deleteNode
returns the root node of the tree, which could be a different root than the root on which the call was made (when the root node was deleted), or even None
when that was the last node of the tree.
Here is how that would look:
def deleteNode(self,val):
if self.data > val:
if self.left:
self.left = self.left.deleteNode(val)
elif self.data < val:
if self.right:
self.right = self.right.deleteNode(val)
else:
if self.left is None:
return self.right
elif self.right is None:
return self.left
else:
largest = self.left.findMax()
self.data = largest
self.left = self.left.deleteNode(largest)
return self
To do it right, you would need to use the return value from this method, for example:
t1 = t1.deleteNode(34)
NB: In some methods you check whether self.data is None
. I understand this is some special condition for indicating that the root node is not really a node, and should be considered an empty tree, but this is not a nice pattern. Instead, an empty tree should be just None
, or you should define another Tree
class which has a root
attribute which can be None
.