Binary Search trees implementation using python - 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

Related

How can I run this Height of a BST tree function

can someone help me out with this? I implemented a binary search tree data structure in python and I wrote a BST_height() function to calculate the height of the tree. But when I ran my code, It gave me an error saying 'self is not defined'. I know why the error is showing up but can you suggest some other way to run the BST_height function with the root node
class Node:
def __init__(self, data=None):
self.data = data
self.left = None
self.right = None
class BinarySearchTree:
def __init__(self):
self.root = Node()
def display(self):
print('''
{}
/ \\
{} {}
/ \\ / \\
{} {} {} {}
BINARY TREE
'''.format(tree.root.data, tree.root.left.data, tree.root.right.data, tree.root.left.left.data, tree.root.right.right.data, tree.root.left.right.data, tree.root.right.left.data))
def checkRoot(self):
if self.root.data != None:
return 'Root node exists'
else:
return 'Root node doesn\'t exists'
def insert(self, data):
newNode = Node(data)
if self.root.data == None:
# creating the root node
self.root = newNode
else:
self.insertNode(data, self.root)
def insertNode(self, data, curNode):
if data < curNode.data:
if curNode.left == None:
curNode.left = Node(data)
else:
self.insertNode(data, curNode.left)
elif data > curNode.data:
if curNode.right == None:
curNode.right = Node(data)
else:
self.insertNode(data, curNode.right)
else:
print('The value already exists ha ha')# funny
def BST_height(self, node):
if node == None:
return -1
leftHeight = height(node.left)
rightHeight = height(node.right)
return max(leftHeight, rightHeight) + 1
tree = BinarySearchTree()
tree.insert(30)# root node
tree.insert(24)
tree.insert(45)
tree.insert(90)
tree.insert(18)
tree.insert(28)
tree.insert(40)
tree.display()
# getting an error here
# I know self.root can\'t be used outside the class but can you suggest some other way tree.BST_height(self.root)
There are 2 problems with the code:
Self is something you use inside of class functions. Outside you can simply use the object variable. like so:
tree.BST_height(tree.root)
BST_height function has a small error in it. It calls height instead of self.BST_height:
def BST_height(self, node):
if node == None:
return -1
leftHeight = self.BST_height(node.left)
rightHeight = self.BST_height(node.right)
return max(leftHeight, rightHeight) + 1
You might want to read this for clarity on the whole self topic.

I'm trying to implement Binary Tree insert method with recursive calls

I'm trying to implement Binary Tree insert method with recursive calls. When i run insert function it gives me an AtributeError : BinTree instance has no atribute 'root. Can you tell me pls how I can fix it??
from random import randint
class Node:
def __init__(self,value):
self.value = value
self.left = None
self.right = None
class BinTree:
def __init___(self):
self.root = None
def insert(self, value):
if self.root == None:
self.root = Node(value)
else:
self._insert(value, self.root)
def _insert(self, value, curr_node):
if value < curr_node.value:
if curr_node.left == None:
curr_node.left = Node(value)
else:
self._insert(value, curr_node.left)
elif value>curr_node.value:
if curr_node.right == None:
curr_node.right = Node(value)
else:
self._insert(value, curr_node.rigth)
else:
print('Node already exist!')
def printTree(self):
if self.root != None:
self._printTree(self.root)
def _printTree(self, curr_node):
if curr_node !=None:
self._printTree(curr_node.left)
print(str(curr_node.val))
self._printTree(curr_node.right)
def fillTree(tree):
for _ in range(100):
curr_elem = randint(0,50)
tree.insert(curr_elem)
return tree
tree = BinTree()
fillTree(tree)
tree.printTree()
Your __init__ has a typo in the name. There are 3 trailing underscores. Change it to:
...
class BinTree:
def __init__(self):
self.root = None
And your code should work
Edit: found a couple of more issues. Here's the complete fixed code:
from random import randint
class Node:
def __init__(self,value):
self.value = value
self.left = None
self.right = None
class BinTree:
def __init__(self):
self.root = None
def insert(self, value):
if self.root == None:
self.root = Node(value)
else:
self._insert(value, self.root)
def _insert(self, value, curr_node):
if value < curr_node.value:
if curr_node.left == None:
curr_node.left = Node(value)
else:
self._insert(value, curr_node.left)
elif value>curr_node.value:
if curr_node.right == None:
curr_node.right = Node(value)
else:
self._insert(value, curr_node.right)
else:
print('Node already exist!')
def printTree(self):
if self.root != None:
self._printTree(self.root)
def _printTree(self, curr_node):
if curr_node !=None:
self._printTree(curr_node.left)
print(str(curr_node.value))
self._printTree(curr_node.right)
def fillTree(tree):
for _ in range(100):
curr_elem = randint(0,50)
tree.insert(curr_elem)
return tree
tree = BinTree()
fillTree(tree)
tree.printTree()
Only BinTrees have roots; the children of a BinTree are Nodes, not BinTrees and thus don't have roots.

Cannot Delete the root node in a Binary search Tree

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

How can I find visited nodes called in functions?

Here's my programme of Binary Search Tree, all the functions are working in uploading system, except the last one, I somehow have to find out which of the Nodes I visited throughout calling previous functions. Any ideas?
class Node:
def __init__(self, value):
self.left = None
self.right = None
self.data = value
class BinarySearchTree:
def __init__(self):
self.root = None
def insert(self, value):
if self.root is None:
self.root = Node(value)
else:
self._insert(value, self.root)
def _insert(self, value, curNode):
if value < curNode.data:
if curNode.left is None:
curNode.left = Node(value)
else:
self._insert(value, curNode.left)
else:
if curNode.right is None:
curNode.right = Node(value)
else:
self._insert(value, curNode.right)
def fromArray(self, array):
for i in range(len(array)-1):
value = array[i]
self.insert(value)
i += 1
def search(self, value):
if self.root is not None:
return self._search(value, self.root)
else:
return False
def _search(self, value, curNode):
if value == curNode.data:
return True
elif value < curNode.data and curNode.left is not None:
self._search(value, curNode.left)
elif value > curNode.data and curNode.right is not None:
self._search(value, curNode.right)
else:
return False
def min(self):
curNode = self.root
while curNode.left is not None:
curNode = curNode.left
return curNode
def max(self):
curNode = self.root
while curNode.right is not None:
curNode = curNode.right
return curNode
def visitedNodes(self):
pass
And it has to return the values of nodes in list.
The straight forward answer would be to add a visited flag to each node, that is explicitly flipped in each of your functions when a Node is visited:
class Node:
def __init__(self, value):
self.left = None
self.right = None
self.data = value
self.visited = False
and then:
def _search(self, value, curNode):
curNode.visited = True
if value == curNode.data:
return True
# etc., unchanged
Same for min and max, and finally:
def visitedNodes(self, current=self.root, accumulator=[]):
if current == None:
return
if current == self.root:
accumulator = []
if current.visited:
accumulator.append(current)
visitedNodes(current.left)
visitedNodes(current.right)
return accumulator
This is just one implementation, there are many other ways to do this. I also assume this function, which traverses the whole tree, should not set the visited flag.
If you don't want to modify your current code, maybe this can help you:
class Node:
def __init__(self, value):
self.left = None
self.right = None
self._data = value
self.visited = False
#property
def data(self):
self.visited = True
return self._data
#data.setter
def data(self, value):
self.visited = False
self._data = value
n = Node(3)
print(n.visited)
print(n.data)
print(n.visited)
Output:
False
3
True
Then in your visitedNodes method you would have to look at the visited attribute of everynode. (Which will be slow)
Other way of doing it is adding a new set attribute to your BinarySearchTree and manually add a node each time you look at it, this will make you modify your code.

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)

Categories

Resources