Binary search tree with python generators - python

I got the problem to find the height from a partially completed code sample of BST implementation as below.
class BST:
class Node:
def __init__(self, key, left=None, right=None):
self.key = key
self.left = left
self.right = right
def __iter__(self):
if self.left:
yield from self.left
yield self.key
if self.right:
yield from self.right
def __init__(self, root=None):
self.root = root
def __iter__(self):
if self.root:
yield from self.root
def insert(self, key):
self.root = self._insert(self.root, key)
def _insert(self, r, key):
if r is None:
return self.Node(key)
elif key < r.key:
r.left = self._insert(r.left, key)
elif key > r.key:
r.right = self._insert(r.right, key)
else:
pass
return r
def print(self):
self._print(self.root)
def _print(self, r):
if r:
self._print(r.left)
print(r.key, end=' ')
self._print(r.right)
def contains(self, k):
n = self.root
while n and n.key != k:
if k < n.key:
n = n.left
else:
n = n.right
return n is not None
def size(self):
return self._size(self.root)
def _size(self, r):
if r is None:
return 0
else:
return 1 + self._size(r.left) + self._size(r.right)
I tried to implement "def height(self): " method, referencingBinary search tree
I tried left and right nodes as below
for node in self.root.__iter__():
print(node)
But, I was unable to understand how to work with generators and implement this height method.Hope your support. Thanks in advance.

Related

Trouble calling height() on a binary tree

I'm writing a function to check if a binary tree satisfies the Height-Balance Property. This is my code but I'm having trouble calling the height function for left and right from my given LinkedBinaryTree class. The main thing that's confusing me is that the nested function takes the root a parameter but height() doesn't. For reference, bin_tree is a LinkedBinaryTree() not a node. Thank you in advance for any help!
My Code
from LinkedBinaryTree import LinkedBinaryTree
def is_height_balanced(bin_tree):
if bin_tree.root is None:
return True
left = bin_tree.height()
right = bin_tree.height()
if abs(left - right) <= 1:
if is_height_balanced(bin_tree.root.left) is True and is_height_balanced(bin_tree.root.right) is True:
return True
return False
Portion of LinkedBinaryTree class
class LinkedBinaryTree:
class Node:
def __init__(self, data, left=None, right=None):
self.data = data
self.parent = None
self.left = left
if (self.left is not None):
self.left.parent = self
self.right = right
if (self.right is not None):
self.right.parent = self
def __init__(self, root=None):
self.root = root
self.size = self.count_nodes()
# assuming count_nodes() and is_empty() works as expected
def height(self):
def subtree_height(root):
if (root.left is None and root.right is None):
return 0
elif (root.left is None):
return 1 + subtree_height(root.right)
elif (root.right is None):
return 1 + subtree_height(root.left)
else:
left_height = subtree_height(root.left)
right_height = subtree_height(root.right)
return 1 + max(left_height, right_height)
if(self.is_empty()):
raise Exception("Tree is empty")
return subtree_height(self.root)

Maximum recursion with large lists

I am making a binary tree with a very large list, almost 10000 objects. The issue is that I get a maximum recursion error due to the huge size. It happens specifically in the binarytree class where TreeNode is being called to create new objects. I am unsure how to implement this without recursion, as it seems to be the easiest way to implement the code.
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
Binary Tree:
class BinarySearchTree:
def __init__(self):
self.root = None
self.size = 0
def length(self):
return self.size
def __len__(self):
return self.size
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 __setitem__(self,k,v):
self.put(k,v)
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 __contains__(self,key):
if self._get(key,self.root):
return True
else:
return False
It is fairly simple to convert your recursive methods to iterative ones, e.g.:
def get(self, key):
node = self.root
while node:
if node.key == key:
return node.payload
elif key < node.key:
node = node.leftChild
else:
node = node.rightChild
return None
def put(self, key, val):
if not self.root:
self.root = TreeNode(key, val)
else:
self._put(key, val, self.root)
self.size = self.size + 1
def _put(self, key, val, currentNode):
while True:
if key < currentNode.key:
if currentNode.hasLeftChild():
currentNode = currentNode.leftChild
else:
currentNode.leftChild = TreeNode(key, val, parent=currentNode)
break
else:
if currentNode.hasRightChild():
currentNode = currentNode.rightChild
else:
currentNode.rightChild = TreeNode(key, val, parent=currentNode)
break
This gets rid of any recursion (limits) and is just as readable.

Python 3: Binary search tree, size-function not returning number of nodes

I'm implementing a (recursive) binary search tree and I can't get the size function working. This is my code so far:
class BinarySearchTreeNode:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def __str__(self):
return str(self.data)
def add(self, data):
if self.data == data:
return False
elif data < self.data:
if self.left:
return self.left.add(data)
else:
self.left = BinarySearchTreeNode(data)
return True
else:
if self.right:
return self.right.add(data)
else:
self.right = BinarySearchTreeNode(data)
return True
def contains(self, data):
if self.data == data:
return True
elif self.data > data:
if self.left:
return self.left.contains(data)
else:
return False
else:
if self.right:
return self.right.contains(data)
else:
return False
def size(self):
if self.left and self.right:
return 1 + self.left.size() + self.right.size()
elif self.left:
return 1 + self.left.size()
elif self.right:
return 1 + self.right.size()
else:
return 1
class BinarySearchTree:
def __init__(self):
self.root = None
def add(self, data):
if not self.root:
self.root = BinarySearchTreeNode(data)
return True
else:
return self.root.add(data)
def contains(self, data):
if self.root:
return self.root.contains(data)
else:
return False
def clear(self):
self.root = None
def size(self):
if self.root is None:
return 0
else:
return self.root.size()
bst = BinarySearchTree()
bst.add(3)
bst.add(24)
bst.add(7)
bst.add(15)
bst.add(2)
bst.add(19)
bst.size()
I want the size function to be called from the BinarySearchTree class but executed via the BinarySearchTreeNode class. I have tried everything I can think of, but nothing works. What am I doing wrong?
What is this?
class BinarySearchTreeNode:
self.data = data
self.left = None
self.right = None
This is not an initializing process you're doing there mate. Try the following:
class BinarySearchTreeNode:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
Even checked it for you:
In[1]:
bst = BinarySearchTree()
bst.add(3)
bst.add(24)
bst.add(7)
bst.add(15)
bst.add(2)
bst.add(19)
bst.size()
Out[2]: 6

I keep getting this error:RecursionError: maximum recursion depth exceeded while calling a Python object

I am trying to use BFS to search through a tree with three letter words and find the way in between a given start and end word and print the way in between. The printing is supposed to be done with a recursive function.
I keep getting this error:
RecursionError: maximum recursion depth exceeded while calling a Python object
and an infinite loop with the endword can anyone see whats wrong? (I copied my imported classes as well).
from array import array
class Node1:
#håller koll på värdena
def __init__(self, data, next = None):
self.data = data
self.next = next
def __str__(self):
if self.data.parent == None:
return None
else:
print(self.data.parent)
return str(self.data.parent)
def __str__(self):
return str(self.data.word)
class Queue:
def __init__(self):
self.first = None
self.last = None
def enqueue(self,x):
"""Stoppar in x sist i kön """
x = Node1(x)
if self.first == None: # Om kön är tom
self.first = self.last = x
else: # om kön inte är tom
self.last.next = x
self.last = x
def dequeue(self):
first = self.first
self.first = self.first.next
#if self.first == None:
# self.last=None
return first
def isEmpty(self):
if self.first == None:
xx = True
else:
xx = False
#print('I IsEmpty: Första elementet i listan:',self.first)
#print('I IsEmpty: Sista elementet i listan:',self.last)
return xx
def __str__(self):
node=self.first
node_strang = 'Efter trolleriet får man: '
while node != None:
node_strang += str(node)
node = node.next
return node_strang
class Node:
'''Nodklass med rekursiva metoder som anropas i Bintree-klassen'''
def __init__(self, word):
self.word = word
self.left = None
self.right = None
def insert(self, new_word):
if self.word == new_word:
return False
elif new_word < self.word:
if self.left:
return self.left.insert(new_word)
else:
self.left = Node(new_word)
return True
else:
if self.right:
return self.right.insert(new_word)
else:
self.right = Node(new_word)
return True
def find(self, new_word):
if self.word == new_word:
return True
elif new_word < self.word:
if self.left:
return self.left.find(new_word)
else:
return False
else:
if self.right:
return self.right.find(new_word)
else:
return False
def preorder(self):
if self:
print(self.word)
if self.left:
self.left.preorder()
if self.right:
self.right.preorder()
def postorder(self):
if self:
if self.left:
self.left.postorder()
if self.right:
self.right.postorder()
print(self.word)
def inorder(self):
if self:
if self.left:
self.left.inorder()
print(self.word)
if self.right:
self.right.inorder()
from linkedQFile import Queue,Node1
from bintreeFile import Node
import string
class Bintree:
def __init__(self):
self.root = None
def put(self, new_word):
if self.root:
return self.root.insert(new_word)
else:
self.root = Node(new_word)
return True
def __contains__(self, new_word):
if self.root:
return self.root.find(new_word)
else:
return False
class ParentNode:
def __init__(self, word, parent = None):
self.word = word
self.parent = parent
def maketree():
svenska = Bintree()
gamla = Bintree()
with open('word3.txt', 'r') as ordfil:
for rad in ordfil:
ord = rad.strip()
if ord in svenska:
gamla.put(ord)
svenska.put(ord)
ordfil.close()
return svenska,gamla
def writechain(kidzen, paronen):
if paronen is not None:
print(kidzen)
writechain(kidzen, paronen)
else:
pass
def countchain(barn_obj):
if barn_obj.parent==None:
return 0
else:
return 1+countchain(barn_obj.parent)
def makechildren(nod, q, gamla, svenska):
for i in range(3):
bokstavslista = list(nod.data.word)
alfabetslista = list(string.ascii_lowercase) + ['å', 'ä', 'ö']
for bokstav in alfabetslista:
bokstavslista[i] = bokstav
barn = ''.join(bokstavslista)
if barn in svenska:
barn_obj = ParentNode(barn, nod.data)
#print('parent to', barn, 'is', str(barn_obj.parent))
if barn not in gamla:
#print("i makechildren: barn = ", barn)
q.enqueue(barn_obj)
gamla.put(barn_obj.word)
def main():
(svenska,gamla) = maketree()
q=Queue()
start = input('Startord:')
slut = input('Slutord:')
startord= ParentNode(start, parent=None)
q.enqueue(startord)
while not q.isEmpty():
nod = q.dequeue()
makechildren(nod, q, gamla, svenska)
nod_for=nod.data
kidzen=nod_for.word
paronen=nod_for.parent
#print ('word =', kidzen)
#print ('parent =', paronen)
if q.isEmpty():
print('Det finns ingen väg till', slut)
break
elif kidzen==slut:
writechain(kidzen, paronen)
print('Det finns en väg till', slut)
break
main()
In your writechain function you are not walking a tree.
You keep recursively calling it with the same arguments. That will continue until you reach the recursion limit.

Inorder, Preorder, Postorder traversal not working

I am trying to implement binary search tree in pythonand trying to print the nodes of a tree in inorder, preorder and postorder but unfortunately my results are not correct.
Here is my code:
class Node:
def __init__(self, val):
self.v = val
self.l = None
self.r = None
class BinarySearchTree:
def __init__(self):
self.root = None
def get_root(self):
return self.root
def insert(self, val):
if self.root is None:
self.root = Node(val)
else:
self._add(val, self.root)
def _add(self, val, node):
if val < node.l:
if node.l is None:
node.l = Node(val)
else:
self._add(val, node.l)
else:
if node.r is None:
node.r = Node(val)
else:
self._add(val, node.r)
def find(self, val):
if self.root is None:
return None
else:
self._find(val, self.root)
def _find(self, val, node):
if val == node.v:
return Node
else:
if val < node.v and node is not None:
self._find(val, node.l)
if val > node.v and node is not None:
self._find(val, node.r)
def delete_tree(self):
self.root = None
def print_in_order(self): # Left, Node, Right
if self.root is None:
return None
else:
self._in_order(self.root)
def _in_order(self, node):
if node is not None:
self._in_order(node.l)
print str(node.v) + ' '
self._in_order(node.r)
def print_pre_order(self): # Node, Left, Right
if self.root is None:
return None
else:
self._pre_order(self.root)
def _pre_order(self, node):
if node is not None:
print str(node.v) + ' '
self._pre_order(node.l)
self._pre_order(node.r)
def print_post_order(self): # Left, Right, Node
if self.root is None:
return None
else:
self._post_order(self.root)
def _post_order(self, node):
if node is not None:
self._post_order(node.l)
self._post_order(node.r)
print str(node.v) + ' '
if __name__ == '__main__':
t = BinarySearchTree()
t.insert(20)
t.insert(10)
t.insert(30)
t.insert(5)
t.insert(15)
t.insert(25)
t.insert(35)
print 'In Order Traversal: \n', t.print_in_order()
print '\nPre Order Traversal: \n', t.print_pre_order()
print '\nPost Order Traversal:\n', t.print_post_order()
Can someone please tell me what am I doing wrong?
My output is in the following: Inorder and Preorder is returning the same output.
In Order Traversal:
20
10
30
5
15
25
35
None
Pre Order Traversal:
20
10
30
5
15
25
35
None
Post Order Traversal:
35
25
15
5
30
10
20
None
Traversal functions are okay. But in _add, the following comparison:
if val < node.l:
...
should be replaced with:
if val < node.v:
...
to compare new value with current node value, instead of the left node which cause wrong comparison result; results in wrong tree structure.

Categories