Cannot Delete the root node in a Binary search Tree - python

I have recently started learning and Implementing some data structures in Python and was trying Binary Search tree and completed the code.
Everything is running fine except the deletion of root node.
I have divided my code into 3 modules
Here is my Code :
Node.py
class Node:
def __init__(self, data):
self.data = data
self.leftChild = None
self.rightChild = None
def insert(self, data):
if data < self.data:
if not self.leftChild:
self.leftChild = Node(data)
else:
self.leftChild.insert(data)
else:
if not self.rightChild:
self.rightChild = Node(data)
else:
self.rightChild.insert(data)
def remove(self, data, parentNode):
if data < self.data:
if self.leftChild is not None:
self.leftChild.remove(data, self)
elif data > self.data:
if self.rightChild is not None:
self.rightChild.remove(data, self)
else:
if self.leftChild is not None and self.rightChild is not None:
self.data = self.rightChild.getMin()
self.rightChild.remove(self.data, self)
elif parentNode.leftChild == self:
if self.leftChild is not None:
tempNode = self.leftChild
else:
tempNode = self.rightChild
parentNode.leftChild = tempNode
elif parentNode.rightChild == self:
if self.leftChild is not None:
tempNode = self.leftChild
else:
tempNode = self.rightChild
parentNode.rightChild = tempNode
def getMin(self):
if self.leftChild is None:
return self.data
else:
self.leftChild.getMin()
def getMax(self):
if self.rightChild is None:
return self.data
else:
self.rightChild.getMax()
def traverseInOrder(self):
if self.leftChild is not None:
self.leftChild.traverseInOrder()
print(self.data)
if self.rightChild is not None:
self.rightChild.traverseInOrder()
BinarySearchTree.py
from BinarySearchTrees.Node import Node
class BST:
def __init__(self):
self.rootNode = None;
def insert(self, data):
if self.rootNode is None:
self.rootNode = Node(data)
else:
self.rootNode.insert(data)
def removal(self, dataToRemove):
if self.rootNode:
if self.rootNode.data == dataToRemove:
tempNode = Node(None)
tempNode.leftChild = self.rootNode
print("The value of dataToRemove : " + str(dataToRemove))
self.rootNode.remove(dataToRemove, tempNode)
else:
self.rootNode.remove(dataToRemove, None)
def getMin(self):
if self.rootNode:
return self.rootNode.getMin()
def getMax(self):
if self.rootNode:
return self.rootNode.getMax()
def traverseInOrder(self):
if self.rootNode:
self.rootNode.traverseInOrder()
Output.py
from BinarySearchTrees.BinarySearchTree import BST
bst = BST()
bst.insert(5)
bst.insert(8)
bst.insert(3)
bst.insert(7)
bst.insert(9)
bst.insert(4)
bst.insert(2)
bst.traverseInOrder()
bst.removal(5)
bst.traverseInOrder()
and the Error with the Removal command is :
Traceback (most recent call last):
File "G:\Docs\Liclipse Projects\DS\BinarySearchTrees\Output.py", line 16, in <module>
bst.removal(5)
File "G:\Docs\Liclipse Projects\DS\BinarySearchTrees\BinarySearchTree.py", line 24, in removal
self.rootNode.remove(dataToRemove, tempNode)
File "G:\Docs\Liclipse Projects\DS\BinarySearchTrees\Node.py", line 34, in remove
self.rightChild.remove(self.data, self)
File "G:\Docs\Liclipse Projects\DS\BinarySearchTrees\Node.py", line 23, in remove
if data < self.data:
TypeError: '<' not supported between instances of 'NoneType' and 'int'
It's like the data parameter passed in remove function in Node is returning a None value despite of giving a value in the BinarySearchTree removal function.
If anyone could find the error in my code please tell me the solution. It would be a great help..

Both instances of if data < self.data: should be : if data is not None and (data < self.data):
This will short circuit the check when data is not None

Related

Binary Search trees implementation using python

class Node:
def __init__(self, data, parent):
self.leftChild = None
self.rightChild = None
self.parent = parent
self.data = data
class BST:
def __init__(self):
self.root = None
self.count = 0
def insert(self, data):
self.count +=1
if self.root is None:
self.root = Node(data, None)
else:
self.insertNode(data,self.root)
def insertNode(self, data, parentNode):
if data < parentNode.data:
if parentNode.leftChild is not None:
self.insertNode(data, parentNode.leftChild)
else:
parentNode.leftChild = Node(data, parentNode)
else:
if parentNode.rightChild is not None:
self.insertNode(data, parentNode.rightChild)
else:
parentNode.rightChild = Node(data, parentNode)
def get_max(self, node):
if node.rightChild:
self.get_max(node.rightChild)
else:
print(node.data)
# return node.data
# return node.data
def traverse(self):
if(self.root is not None):
self.traverse_InOrder(self.root)
def traverse_InOrder(self, node):
if node.leftChild is not None:
self.traverse_InOrder(node.leftChild)
print(node.data, end=" ")
if node.rightChild is not None:
self.traverse_InOrder(node.rightChild)
bst = BST()
bst.insert(22)
bst.insert(2)
bst.insert(21)
bst.insert(23)
bst.insert(45)
bst.insert(43)
bst.insert(20)
bst.traverse()
print()
bst.get_max(bst.root)
print(bst.get_max(bst.root))
In the get_max function when I'm printing node.data it's working fine, but as soon as I'm returning the data and trying to print it as shown in last line of code, it's returning none.
I don't understand the underlying concept behind it.
Maybe it is something that I'm doing wrong.
Please explain.
Change the get_max function so it returns the rightmost node:
def get_max(self, node):
if node.rightChild:
return self.get_max(node.rightChild)
else:
return node.data

Why is calling function causing a NameError?

I am writing this code below but when I am trying to call the function size() it is throwing error
class Node:
def __init__(self,data):
self.data=data
self.left=None
self.right=None
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)
else:
if self.right is None:
self.right=Node(data)
else:
self.right.insert(data)
else:
self.data=data
def size(node):
if node is None:
return 0
else:
return (size(node.left)+ 1 + size(node.right))
root=Node(4)
root.insert(5)
root.insert(3)
root.insert(8)
print(size(root))
The error below is getting thrown:
NameError Traceback (most recent call last)
<ipython-input-7-8c72ba7719dc> in <module>
41 root.insert(8)
42
---> 43 print(size(root))
44
45 #root.print()
NameError: name 'size' is not defined
Either define size after the class statement:
class Node:
def __init__(self,data):
self.data=data
self.left=None
self.right=None
def insert(self,data):
...
def size(node):
if node is None:
return 0
else:
return (size(node.left)+ 1 + size(node.right))
or make it a proper method:
class Node:
def __init__(self,data):
self.data=data
self.left=None
self.right=None
def insert(self,data):
...
def size(self):
rv = 1
if self.left is not None:
rv += self.left.size()
if self.right is not None:
rv += self.right.size()
return rv
In your Code, size is a method bound to a Node object, so you need to call root.size() (because root is a Node instance)
After some discussion with #ShadowRanger, here is what I came up with.
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
#dataclass
class Node:
data: Any
left: Node = None
right: Node = None
def insert(self, data: Any) -> None:
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
else:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
def num_child_nodes(self) -> int:
num_nodes = 0
if self.left:
num_nodes += 1 + self.left.num_child_nodes()
if self.right:
num_nodes += 1 + self.right.num_child_nodes()
return num_nodes

AVL Tree in python

I am currently having trouble with a AVL tree in Python 3. I have wrote out the source code that I am following which is on a video, but it is acting strange and I have no idea why.
Here is the code:
class Node(object):
def __init__(self, data, parentNode):
self.data = data
self.parentNode = parentNode
self.rightChild = None
self.leftChild = None
self.balance = 0
def insert(self, data, parentNode):
if data < self.data:
if not self.leftChild:
self.leftChild = Node(data, parentNode)
else:
self.leftChild.insert(data, parentNode)
else:
if not self.rightChild:
self.rightChild = Node(data, parentNode)
else:
self.rightChild.insert(data, parentNode)
return parentNode
def traverseInOrder(self):
if self.leftChild:
self.leftChild.traverseInOrder()
print(self.data)
if self.rightChild:
self.rightChild.traverseInOrder()
def getMax(self):
if not self.rightChild:
return self.data
else:
return self.rightChild.getMax()
def getMin(self):
if not self.leftChild:
return self.data
else:
return self.leftChild.getMin()
class BalancedTree(object):
def __init__(self):
self.rootNode = None
def insert(self, data):
parentNode = self.rootNode
if self.rootNode == None:
parentNode = Node(data, None)
self.rootNode = parentNode
else:
parentNode = self.rootNode.insert(data, self.rootNode)
self.rebalanceTree(parentNode)
def rebalanceTree(self, parentNode):
self.setBalance(parentNode)
if parentNode.balance < -1:
if self.height(parentNode.leftChild.leftChild) >= self.height(parentNode.leftChild.rightChild):
parentNode = self.rotateRight(parentNode)
else:
parentNode = self.rotateLeftRight(parentNode)
elif parentNode.balance > 1:
if self.height(parentNode.rightChild.rightChild) >= self.height(parentNode.rightChild.leftChild):
parentNode = self.rotateLeft(parentNode)
else:
parentNode = self.rotateRightLeft(parentNode)
if parentNode.parentNode is not None:
self.rebalanceTree(parentNode.parentNode)
else:
self.rootNode = parentNode
def rotateLeftRight(self, node):
print("Rotation left right....")
node.leftChild = self.rotateLeft(node.leftChild)
return self.rotateRight(node)
def rotateRightLeft(self, node):
print("Rotation right left....")
node.rightChild = self.rotateRight(node.rightchild)
return self.rotateLeft(node)
def rotateLeft(self, node):
print("Rotate left....")
b = node.rightChild
b.parentNode = node.parentNode
node.rightChild = b.leftChild
if node.rightChild is not None:
node.rightChild.parentNode = node
b.leftChild = node
node.parentNode = b
if b.parentNode is not None:
if b.parentNode.rightChild == node:
b.parentNode.rightChild = b
else:
b.parentNode.leftChild = b
self.setBalance(node)
self.setBalance(b)
return b
def rotateRight(self, node):
print("Rotation right....")
b = node.leftChild
b.parentNode = node.parentNode
node.leftChild = b.rightChild
if node.leftChild is not None:
node.leftChild.parentNode = node
b.rightChild = node
node.parentNode = b
if b.parentNode is not None:
if b.parentNode.rightChild == node:
b.parentNode.rightChild = b
else:
b.parentNode.leftChild = b
self.setBalance(node)
self.setBalance(b)
return b
def setBalance(self, node):
node.balance = (self.height(node.rightChild) - self.height(node.leftChild))
def height(self, node):
if node == None:
return -1
else:
return 1 + max(self.height(node.leftChild), self.height(node.rightChild))
As I test this, this is what happens.
I create a tree:
tree = BalancedTree()
I then try to insert 3 intergers.
tree.insert(4)
tree.insert(2)
Now when I enter the third interger.
tree.insert(3)
I get this output without calling any functions.
Rotation left right....
Rotate left....
Rotation right....
That is what happens. I try to traverse the tree. I receive this error.
Traceback (most recent call last): File "", line 1, in
tree.traverseInOrder() AttributeError: 'BalancedTree' object has no attribute 'traverseInOrder'
Yet the video I am following his code works fine. I am lost as I have relooked over the code to see if I made a mistake somewhere and doesn't seem like I have. What am I missing? In his code there is no traverseInOrder function for the tree itself. Yet he is able to call it and run it just fine. Can someone explain why this is happening? Please and thank you.
The immediate problem is that your indentation is incorrect for the usage you give. As posted, class node consists of only this:
class Node(object):
def __init__(self, data, parentNode):
self.data = data
self.parentNode = parentNode
self.rightChild = None
self.leftChild = None
self.balance = 0
Then you have a few independent functions, followed by your trivial balancedTree class, and a few other independent functions.
However, this wouldn't allow you to insert a value the way you've done it, so it appears that the posted code is not what produced the output you give.
UPDATE
I fixed the indentation. The code appears to properly insert and balance the tree of 3 nodes. However, there is no error. The line of code you cite,
tree.traverseInOrder()
does not appear in your posted code. Without accurate code and the full error message, including the full traceback, we can't debug your problem.
I also tried adding that line at the bottom of your code, and finally got the error message you cite. The run-time system is correct (no surprise): there is no traverseInOrder method for class BalancedTree. That name does exist for class Node, but that's not what you called. You've confused your two classes. Sort this out, and the code may well work.

Insert not persisting in tree

I'm trying to implement a BST, and am working on insert. I want to be able to call something simple, like tree.insert(Node(1)). But the issue is that this binaryInsert doesn't persist. What's the best way to achieve this functionality?
class Node:
def __init__(self, data):
self.value = data
self.rightChild = None
self.leftChild = None
class Tree:
def __init__(self):
self.root = None
def binaryInsert(self, root, node):
if root == None:
root = node
else:
if root.value > node.value:
if root.leftChild == None:
root.leftChild = node
else:
self.binaryInsert(root.leftChild, node)
else:
if root.rightChild == None:
root.rightChild = node
else:
self.binaryInsert(root.rightChild, node)
def insert(self, node):
self.binaryInsert(self.root, node)
consider these lines from your code:
def binaryInsert(self, root, node):
if root == None:
root = node
here you are just overriding a local root variable (scoped to the method), I've corrected your code, feel free to ask any question:
class Node:
def __init__(self, data):
self.value = data
self.rightChild = None
self.leftChild = None
class Tree:
def __init__(self):
self.root = None
def binaryInsert(self, tree, node):
if tree.root == None:
tree.root = node
else:
if tree.root.value > node.value:
if tree.root.leftChild == None:
tree.root.leftChild = node
else:
self.binaryInsert(tree.root.leftChild, node)
else:
if tree.root.rightChild == None:
tree.root.rightChild = node
else:
self.binaryInsert(tree.root.rightChild, node)
def insert(self, node):
self.binaryInsert(self, node)

Recursion with large text file

I am trying to read in a large text file (1.08 MB with 116253 words) and I am running into a problem with the program stopping about 1/20th of the way into the text file (Stopping in the Read function and not even executing the print statement).
Here is the function as I have it now:
from binary_search_tree import BinarySearchTree
from tree_node import TreeNode
import sys
sys.setrecursionlimit(5000000)
MovieTree = BinarySearchTree()
def Read(filename):
file = open('movieData.txt')
for line in file:
MovieTree[line.strip()] = line
print(line)
file.close()
Read('movieData.txt')
print(MovieTree)
The binary_search_tree and tree_node where given to me as this is a homework assignment so I am under the assumption that is works because it has been used before.
Does anyone have any idea as to what the problem is?
Binary Search Tree:
from tree_node import TreeNode
class BinarySearchTree:
def __init__(self):
self.root = None
self.size = 0
def length(self):
return self.size
def __len__(self):
return self.size
def __iter__(self):
return self.root.__iter__()
def __str__(self):
"""Returns a string representation of the tree
rotated 90 degrees counter-clockwise"""
def strHelper(root, level):
resultStr = ""
if root:
resultStr += strHelper(root.rightChild, level+1)
resultStr += "| " * level
resultStr += str(root.key) + "\n"
resultStr += strHelper(root.leftChild, level+1)
return resultStr
return strHelper(self.root, 0)
def __contains__(self,key):
if self._get(key,self.root):
return True
else:
return False
def get(self,key):
if self.root:
res = self._get(key,self.root)
if res:
return res.payload
else:
return None
else:
return None
def _get(self,key,currentNode):
if not currentNode:
return None
elif currentNode.key == key:
return currentNode
elif key < currentNode.key:
return self._get(key,currentNode.leftChild)
else:
return self._get(key,currentNode.rightChild)
def __getitem__(self,key):
return self.get(key)
def __setitem__(self,k,v):
self.put(k,v)
def put(self,key,val):
if self.root:
self._put(key,val,self.root)
else:
self.root = TreeNode(key,val)
self.size = self.size + 1
def _put(self,key,val,currentNode):
if key < currentNode.key:
if currentNode.hasLeftChild():
self._put(key,val,currentNode.leftChild)
else:
currentNode.leftChild = TreeNode(key,val,
parent=currentNode)
else:
if currentNode.hasRightChild():
self._put(key,val,currentNode.rightChild)
else:
currentNode.rightChild = TreeNode(key,val,
parent=currentNode)
def delete(self,key):
if self.size > 1:
nodeToRemove = self._get(key,self.root)
if nodeToRemove:
self.remove(nodeToRemove)
self.size = self.size-1
else:
raise KeyError('Error, key not in tree')
elif self.size == 1 and self.root.key == key:
self.root = None
self.size = self.size - 1
else:
raise KeyError('Error, key not in tree')
def __delitem__(self,key):
self.delete(key)
def remove(self,currentNode):
if currentNode.isLeaf(): #leaf
if currentNode == currentNode.parent.leftChild:
currentNode.parent.leftChild = None
else:
currentNode.parent.rightChild = None
elif currentNode.hasBothChildren(): #interior
succ = currentNode.findSuccessor()
succ.spliceOut()
currentNode.key = succ.key
currentNode.payload = succ.payload
else: # this node has one child
if currentNode.hasLeftChild():
if currentNode.isLeftChild():
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.leftChild
elif currentNode.isRightChild():
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.leftChild
else:
currentNode.replaceNodeData(currentNode.leftChild.key,
currentNode.leftChild.payload,
currentNode.leftChild.leftChild,
currentNode.leftChild.rightChild)
else:
if currentNode.isLeftChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.rightChild
elif currentNode.isRightChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.rightChild
else:
currentNode.replaceNodeData(currentNode.rightChild.key,
currentNode.rightChild.payload,
currentNode.rightChild.leftChild,
currentNode.rightChild.rightChild)
TreeNode:
class TreeNode:
def __init__(self,key,val,left=None,right=None,
parent=None):
self.key = key
self.payload = val
self.leftChild = left
self.rightChild = right
self.parent = parent
def hasLeftChild(self):
return self.leftChild
def hasRightChild(self):
return self.rightChild
def isLeftChild(self):
return self.parent and \
self.parent.leftChild == self
def isRightChild(self):
return self.parent and \
self.parent.rightChild == self
def isRoot(self):
return not self.parent
def isLeaf(self):
return not (self.rightChild or self.leftChild)
def hasAnyChildren(self):
return self.rightChild or self.leftChild
def hasBothChildren(self):
return self.rightChild and self.leftChild
def replaceNodeData(self,key,value,lc,rc):
self.key = key
self.payload = value
self.leftChild = lc
self.rightChild = rc
if self.hasLeftChild():
self.leftChild.parent = self
if self.hasRightChild():
self.rightChild.parent = self
def __iter__(self):
if self:
if self.hasLeftChild():
for elem in self.leftChild:
yield elem
yield self.key
if self.hasRightChild():
for elem in self.rightChild:
yield elem
def findSuccessor(self):
succ = None
if self.hasRightChild():
succ = self.rightChild.findMin()
else:
if self.parent:
if self.isLeftChild():
succ = self.parent
else:
self.parent.rightChild = None
succ = self.parent.findSuccessor()
self.parent.rightChild = self
return succ
def findMin(self):
current = self
while current.hasLeftChild():
current = current.leftChild
return current
def spliceOut(self):
if self.isLeaf():
if self.isLeftChild():
self.parent.leftChild = None
else:
self.parent.rightChild = None
elif self.hasAnyChildren():
if self.hasLeftChild():
if self.isLeftChild():
self.parent.leftChild = self.leftChild
else:
self.parent.rightChild = self.leftChild
self.leftChild.parent = self.parent
else:
if self.isLeftChild():
self.parent.leftChild = self.rightChild
else:
self.parent.rightChild = self.rightChild
self.rightChild.parent = self.parent
1.08 MB is a small file. Why do you want to use BinarySearchTree? You can easily handle this by dumping the data into a dictionary.
If BinarySearchTree is part of the assignment, it looks to me it has bug. I'd start tracing from its _put() method.
By the way you should not use sys.setrecursionlimit(5000000) to get around the problem. A decent binary search will not hit this limit unless the size of your data is in the order of magnitude of 2^5000000. For the 116253 words that you have a balanced binary tree should only need 12 level of recursion.
Crashes here too with a stack-overflow.
Since your code doesn't contain recursion it must be within the classes your teacher gave you. I think the overflow happens in the put(self, key, val) method.
I'm afraid I barely know Python so I can't give you any futher help.

Categories

Resources