Binary Search Tree Inorder Traversal Python giving recursion Error - python

I am trying to implement Binary Tree, I think the tree implementation is working fine as I am able to find my elements using if 8 in tree. But I when I am trying to perform inOrder Traversal I am running into Recursion Error.
class BinaryNode:
def init(self,value):
self.value = value
self.left = None
self.right = None
class BinaryTree:
def __init__(self):
self.root = None
def add(self, value):
if self.root == None:
self.root = BinaryNode(value)
else:
current = self.root
while 1:
if value <= current.value:
if current.left:
current = current.left
else:
current.left = BinaryNode(value)
break
elif value > current.value:
if current.right:
current = current.right
else:
current.right = BinaryNode(value)
break
else:
break
def __contains__(self, target):
node = self.root
while node is not None:
if node is not None:
if target < node.value:
node = node.left
elif target > node.value:
node = node.right
else:
return True
return False
def inorder(self,node):
node = self.root
if node is not None:
self.inorder(node.left)
print (node.value)
self.inorder(node.right)
</code>
tree = BinaryTree()
arr = [8,3,1,6]
for i in arr:
tree.add(i)
print (tree.root.value)
print ('Inorder Traversal')
tree.inorder(tree.root)
Error I am getting is "RecursionError: maximum recursion depth exceeded" :( I am trying to check that node is not none before the call, not sure where I am going wrong

Related

BST with connection to parent - loop

I have problem with infinite loop in getMinimal() method. It works in this way :
1)Take node,
2)If node has other node on the left - go to other one.
3)Repeat as far as node has sth on the left side
4)Return the minimal node.
But sometimes it works in infinite loop for example from 1000 to 400, then to 4 then..to 1000! I have no ide where I make mistake. I reviewed this code many times,every single "pointer" to parent/left/right node is okay! Please - help.
Algorithm works okay to "handwritten" trees - ~20nodes. I wanted to test it in better cases - 2500nodes,generated by random lib (from -10k to 10k).
import random
class Node:
def __init__(self, val):
self.val = val
self.parent = None
self.right = None
self.left = None
# Class of node.
def str(self):
return str(self.val)
class MyTree:
def __init__(self, node):
self.root = node
def insert(self, node):
current = self.root
a = True
while a:
if node.val > current.val:
if current.right is not None:
current = current.right
continue
else:
current.right = node
node.parent = current
a = False
if node.val <= current.val:
if current.left is not None:
current = current.left
continue
else:
current.left = node
node.parent = current
a = False
def search(self, node):
current = self.root
while node.val != current.val:
if node.val > current.val:
current = current.right
continue
elif node.val <= current.val:
current = current.left
continue
if node.val == current.val:
return current
else:
print("There is no such node!")
def delete(self, node):
if isinstance(node, (float, int)):
node = self.search(node)
if node is self.root:
self.__deleteRoot()
return
else:
if node.right is None and node.left is None:
self.__deleteNN(node)
return
if node.right is None and node.left is not None:
self.__deleteLN(node)
return
if node.right is not None and node.left is None:
self.__deleteNR(node)
return
if node.right is not None and node.left is not None:
self.__deleteLR(node)
return
def __deleteNN(self, node):
if node.parent.left is node:
node.parent.left = None
if node.parent.right is node:
node.parent.right = None
def __deleteLN(self, node):
parent = node.parent
son = node.left
# parent replaced
if parent.left is node:
parent.left = son
if parent.right is node:
parent.right = son
son.parent = parent
def __deleteNR(self,node):
parent = node.parent
son = node.right
# replace parent
if parent.left is node:
parent.left = son
if parent.right is node:
parent.right = son
son.parent = parent
def __deleteLR(self, node):
minimal = self.getMinimal(node.right)
if minimal.parent.left is minimal:
minimal.parent.left = None
if minimal.parent.right is minimal:
minimal.parent.right = None
# parent of minimal done..
if node.parent.left is node:
node.parent.left = minimal
if node.parent.right is node:
node.parent.right = minimal
minimal.right = node.right
minimal.left = node.left
def getMinimal(self, node):
k = node
while k.left is not None:
k = k.left
return k
def getMax(self):
current = self.root
while current.right:
current = current.right
return current
def __trav(self, node):
if not node:
return
print(node.val)
self.__trav(node.left)
self.__trav(node.right)
def printTrav(self):
self.__trav(self.root)
def __deleteRoot(self):
if self.root.left is None and self.root.right is None:
self.root = None
return
if self.root.left is None and self.root.right is not None:
# left empty,right full
self.root.right.parent = None
self.root = self.root.right
return
if self.root.left is not None and self.root.right is None:
# right empty, left full
self.root.left.parent = None
self.root = self.root.left
return
# node has both children
if self.root.left is not None and self.root.right is not None:
temp = self.getMinimal(self.root.right) # minimal from right subtree
# sometimes it could be like this..
# r
# \
# x
if temp.parent.left is temp:
temp.parent.left = None
else:
temp.parent.right = None
self.root.left.parent = temp
self.root.right.parent = temp
temp.right = self.root.right
temp.left = self.root.left
self.root = temp
self.root.parent = None
return
def search(self, val):
node = self.root
if node.val == val:
return node
if val > node.val and node.right is not None:
node = node.right
if val < node.val and node.left is not None:
node = node.left
else:
print("There's no such value!")
return
def printMax(self):
print(self.getMax().val)
def printMin(self):
print(self.getMinimal(self.root).val)
arr=[None]*2500
for x in range(2500):
arr[x]=Node(random.randint(-10000,10000))
myTree = MyTree(arr[0])
for x in range(1,2500):
myTree.insert(arr[x])
for x in range(2500):
myTree.delete(arr[x])
It is suspicious that you define search twice.
Still that said, here is how I would debug this. I would modify your program to read from a file, try to run, and then detect an endless loop and bail out. Now write random files until you have one that causes you to crash.
Once you have a random file that shows the bug, the next step is to make it minimal. Here is a harness that can let you do that.
import itertools
flatten = itertools.chain.from_iterable
# bug_found should be a function that takes a list of elements and runs your test.
# example should be an array that demonstrates the bug.
def find_minimal (bug_found, example):
parts = [example]
while 1 < max(len(part) for part in parts):
i = 0
while i < len(parts):
if 1 == len(parts[i]):
i = i + 1
else:
part = parts.pop(i)
# Divide in 2.
mid = len(part)/2
part1 = part[0:mid]
part2 = part[mid:len(part)]
# Do we need part1?
parts.insert(i, part1)
if bug_found(flatten(parts)):
i = i + 1
parts.insert(i, part2)
else:
parts[i] = part2
# Do we need part2?
if bug_found_func(flatten(parts)):
i = i + 1
else:
parts.pop(i)
return list(flatten(parts))
Just let it run, and after some time it is likely to find a small example. Which will greatly aid in debugging.
So - I found 2 serious bugs in code. Both in LR ("standard" node and root). As I suspected - bugs were in pointers. Now tree is working (tested few times for 20k,30k and 100k nodes). Solved.

Maximum recursion depth exceeded error in Python while implementing Binary Search Tree

I was using Python to learn BST and tried implementing insert and find methods. But I was getting Maximum recursion depth exceeded error in insertNode method. I am new to BST data structure and hence struggling to implement the methods in Python. I tried researching and making my code similar to ones on the internet, but I am still getting the error.
class Node:
def __init__(self,data):
self.data = data
self.left = None
self.right = None
class BST:
def __init__(self):
self.root = None
def insert(self,data):
temp = Node(data)
if self.root is None:
self.root = temp
else:
self.insertNode(self.root,data)
def insertNode(self,root,data):
temp = Node(data)
if data < self.root.data:
if self.root.left is None:
self.root.left = temp
else:
self.insertNode(self.root.left,data)
elif data > self.root.data:
if self.root.right is None:
self.root.right = temp
else:
self.insertNode(self.root.right,data)
def findinTree(self,root,data):
if self.root is None:
return False
if data == self.root.data:
return True
if data < self.root.data:
self.findinTree(self.root.left,data)
else:
self.findinTree(self.root.right,data)
return False
bst = BST()
bst.insert(30)
bst.insert(10)
bst.insert(50)
bst.insert(90)
bst.insert(100)
bst.insert(15)
Please help debug the error so that the functions work as intended.
These methods might be the root ;-) cause of the problem:
def insertNode(self, root, data):
if data < root.data: # <- use the root parameter ...
if root.left is None:
root.left = Node(data)
else:
self.insertNode(root.left, data)
else:
if root.right is None:
root.right = Node(data)
else:
self.insertNode(root.right, data)
def findinTree(self, root, data):
if root is None:
return False
if data == root.data:
return True
if data < root.data:
return self.findinTree(root.left, data)
else:
return self.findinTree(root.right, data)
NB code not tested
Update: took suggestion of VPfB and did not create unnecessary nodes.
In insertNode you refer to self.root which is the tree's root. Instead, you should refer root, the function parameter.
In fact, after the 1st sub-level is created (bst.insert(50)), the right branch of the tree's root is not None anymore and so it keeps calling self.insertNode(self.root.right,data)
def insertNode(self,root,data):
temp = Node(data)
if data < root.data:
if root.left is None:
print("Inserting {} on the left branch of {}".format(data, root.data))
root.left = temp
else:
print("Inserting {} on the left branch of {}".format(data, root.data))
self.insertNode(root.left,data)
elif data > root.data:
if root.right is None:
print("Inserting {} on the right branch of {}".format(data, root.data))
root.right = temp
else:
print("Inserting {} on the right branch of {}".format(data, root.data))
self.insertNode(root.right,data)

Python Serializing/Deserializing a binary tree

I'm trying to implement a serializing/deserializing algorithm in python for binary trees.
Here's my code:
class Node:
count = 1
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def insert(self, value):
if self.value > value:
if self.left is None:
self.left = Node(value)
Node.count += 1
else:
self.left.insert(value)
else:
if self.right is None:
self.right = Node(value)
Node.count += 1
else:
self.right.insert(value)
# Using preorder
def serialize(root, serial):
if root != None:
serial.append(root.value)
serialize(root.left, serial)
serialize(root.right, serial)
else:
serial.append('x')
def deserialize(newRoot, serial):
if serial[0] == 'x':
serial.pop(0)
else:
if len(serial) > 0:
newRoot = Node(serial.pop(0))
print(newRoot.value)
deserialize(newRoot.left, serial)
deserialize(newRoot.right, serial)
print("This program serializes a tree\n")
root = Node(3)
root.insert(1)
root.insert(2)
root.insert(4)
root.insert(5)
root.insert(0)
# Serialize
serial = []
serialize(root, serial)
print(serial)
# Deserialize
newRoot = Node(None)
deserialize(newRoot, serial)
print(newRoot.value)
The problem is, newRoot doesn't get updated by deserialize because python passes it by value. How do I get around this, preferably in the most elegant way? In C/C++, I would just pass a pointer to newRoot and it should get updated accordingly. Thanks!
You can return the newly created nodes and assign them as left and right nodes. Also poping the first element of a list is more costly than poping the last element, so reverseing the list at the beginning and then using it in the recursion will be more performant in your case. So the code will become something like:
def deserialize(serial):
serial.reverse()
return _deserialize(serial)
def _deserialize(serial):
if not serial:
return None
node = None
value = serial.pop()
if value != 'x':
node = Node(value)
node.left = _deserialize(serial)
node.right = _deserialize(serial)
return node
root = deserialize(serial)
print(root.value)
You can create left and right subtree within deserialize function and return the root.
Here is my code:
node_list = []
MARKER = -1
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def serialize(root):
if root is None:
node_list.append(MARKER)
return
node_list.append(root.val)
serialize(root.left)
serialize(root.right)
def deserialize(root, node_list):
if node_list:
val = node_list.pop(0)
else:
return
if val == MARKER:
return
# Create root, left and right recursively
root = Node(val)
root.left = deserialize(root.left, node_list)
root.right = deserialize(root.right, node_list)
return root
def inorder_traversal(root):
if root:
inorder_traversal(root.left)
print(root.val, end=' ')
inorder_traversal(root.right)
if __name__=="__main__":
# Create tree
root = Node(20)
root.left = Node(8)
root.right = Node(22)
root.left.left = Node(4)
root.left.right = Node(12)
root.left.right.left = Node(10)
root.left.right.right = Node(14)
print("Inorder traversal before serialization..")
inorder_traversal(root)
print('')
# serialize the tree and insert elements into a list
serialize(root)
print(node_list)
root1 = None
root1 = deserialize(root1, node_list)
print("Inorder traversal after deserialization..")
inorder_traversal(root1)
print('')

Cofusing about lookup node with binary tree

I build a binary tree with python code, now I could print it in order with testTree.printInorder(testTree.root). I have tried to lookup some node ,and the function findNode doesn't work anymore . print testTree.findNode(testTree.root,20) whatever I put in just return None.
class TreeNode:
def __init__(self, value):
self.left = None;
self.right = None;
self.data = value;
class Tree:
def __init__(self):
self.root = None
def addNode(self,node,value):
if node == None:
self.root = TreeNode(value)
else:
if value < node.data:
if node.left == None:
node.left = TreeNode(value)
else:
self.addNode(node.left,value)
else:
if node.right == None:
node.right = TreeNode(value)
else:
self.addNode(node.right,value)
def printInorder(self,node):
if node != None:
self.printInorder(node.left)
print node.data
self.printInorder(node.right)
def findNode(self,node,value):
if self.root != None:
if value == node.data:
return node.data
elif value < node.data and node.left != None:
self.findNode(node.left,value)
elif value > node.data and node.right != None:
self.findNode(node.right,value)
else:
return None
testTree = Tree()
testTree.addNode(testTree.root, 200)
testTree.addNode(testTree.root, 300)
testTree.addNode(testTree.root, 100)
testTree.addNode(testTree.root, 30)
testTree.addNode(testTree.root, 20)
#testTree.printInorder(testTree.root)
print testTree.findNode(testTree.root,20)
Any function without an explicit return will return None.
You have not returned the recursive calls within findNode. So, here.
if value == node.data:
return node.data
elif value < node.data and node.left != None:
return self.findNode(node.left,value)
elif value > node.data and node.right != None:
return self.findNode(node.right,value)
Now, I can't help but thinking this is a bit noisy. You'll always start adding from the root, yes?
testTree.addNode(testTree.root, 200)
You could rather do this
testTree.addNode(200)
And to do that, you basically implement your methods on the TreeNode class instead. So, for the addNode.
You could also "return up" from the recursion, rather than "pass down" the nodes as parameters.
class TreeNode:
def __init__(self, value):
self.left = None
self.right = None
self.data = value
def addNode(self,value):
if self.data == None: # Ideally, should never end-up here
self.data = value
else:
if value < self.data:
if self.left == None:
self.left = TreeNode(value)
else:
self.left = self.left.addNode(value)
else:
if self.right == None:
self.right = TreeNode(value)
else:
self.right = self.right.addNode(value)
return self # Return back up the recursion
Then, in the Tree class, just delegate the addNode responsibility to the root
class Tree:
def __init__(self):
self.root = None
def addNode(self,value):
if self.root == None:
self.root = TreeNode(value)
else:
self.root = self.root.addNode(value)
When you recurse to children in findNode you need to return the result, otherwise the function will implicitly return None:
def findNode(self,node,value):
if self.root != None:
if value == node.data:
return node.data
elif value < node.data and node.left != None:
return self.findNode(node.left,value) # Added return
elif value > node.data and node.right != None:
return self.findNode(node.right,value) # Added return
else:
return None

Mirror Binary Search Tree

This is a code that given a root of the binary search tree, is to create its mirror.
def mirror(root):
if root is None:
pass
else:
mirror(root.left)
mirror(root.right)
temp = root.left
root.left = root.right
root.right = temp
Firstly, is this code right and also is the recursion here supposed to first get to the leaves of the tree first and then switch the references when unwinding?
It's right, but not very Pythonic.
Better to just write
def mirror(root):
if root is None:
return
mirror(root.left)
mirror(root.right)
root.left, root.right = root.right, root.left
For this problem, you could recurse in either order (either reversing the leaves before the parents or after).
Here is my python code to get mirror image of Binary search tree.There might be some incorrect indentations.
#Binary Tree Node
class Node:
def __init__(self,item):
self.data = item
self.left = None
self.right = None
#Binary search tree
class binarySearchTree:
def __init__(self):
self.root = Node(None)
def mirror(self,node):
if node is None:
return False
elif self.root.data == node:
self.root.left,self.root.right = self.root.right,self.root.left
if self.root.left != None:
self._mirror(self.root.left)
if self.root.right != None:
self._mirror(self.root.right)
else:
return self.root
def _mirror(self,node):
if node is None:
return False
else:
node.left,node.right = node.right,node.left
if node.left != None:
self._mirror(node.left)
if node.right != None:
self._mirror(node.right)
else:
return node
def inorder_traverse(self):
if self.root != None:
self._inorder(self.root)
def _inorder(self,cur):
if cur != None:
if cur.left is not None:
self._inorder(cur.left)
print(cur.data)
if cur.right != None:
self._inorder(cur.right)
def main():
bst = binarySearchTree()
bst.insert(7)
bst.insert(1)
bst.insert(0)
bst.insert(3)
bst.insert(2)
bst.insert(5)
bst.insert(4)
bst.insert(6)
bst.insert(9)
bst.insert(8)
bst.insert(10)
bst.insert(11)
bst.inorder_traverse()
bst.mirror(7)
bst.inorder_traverse()
output:
enter image description here

Categories