In my binary search tree I am making a depth function which will tell the user what is the depth of the tree they have insert. This function will be crucial for my unique delete function that deletes a node from the largest depth-sided node. I think I know where the problem is exactly but I'm not sure.
This is my error I keep receiving.
C:\Python33\python.exe "C:/Users/koopt_000/Desktop/College/Sophomore Semester 2/Computer Science 231/Chapter7/Test.py"
Traceback (most recent call last):
PRE-ORDER TRANSVERSE:
File "C:/Users/koopt_000/Desktop/College/Sophomore Semester 2/Computer Science 231/Chapter7/Test.py", line 19, in <module>
4
print("The max depth of the tree is,", a.height(tree),"nodes deep.")
2
File "C:\Users\koopt_000\Desktop\College\Sophomore Semester 2\Computer Science 231\Chapter7\BinarySearchTree.py", line 245, in height
1
3
7
6
5
10
None
IN-ORDER TRANSVERSE:
1
2
3
4
5
6
7
10
None
POST-ORDER TRANSVERSE:
1
return max(BST.height(root.left), BST.height(root.right)) + 1
3
TypeError: height() missing 1 required positional argument: 'root'
2
5
6
10
7
4
None
Process finished with exit code 1
Now I Think my problem arises in this section of code:
return max(BST.height(root.left), BST.height(root.right)) + 1
I believe this statement is what is causing it due to the fact that it is making me call the BST function which the height function is already in for it to 'work'. I simply tried "height.(root.left)", which did not work because it said there is no global variable height. Which isn't the case I don't believe.
Here is my full list of code for my function, starting with my tree node, then my BST file (main), and then my test code.
class TreeNode(object):
def __init__(self, data = None, left=None, right=None):
self.item = data
self.left = left
self.right = right
def __str__(self):
return str(self.item)
from TreeNode import TreeNode
class BST(object):
#------------------------------------------------------------
def __init__(self):
"""create empty binary search tree
post: empty tree created"""
self.root = None
self.size = 0
def delete(self, item):
"""remove item from binary search tree
post: item is removed from the tree"""
self.root = self._subtreeDelete(self.root, item)
#------------------------------------------------------------
def _subtreeDelete(self, root, item):
if root is None: # Empty tree, nothing to do
return None
if item < root.item: # modify left
root.left = self._subtreeDelete(root.left, item)
elif item > root.item: # modify right
root.right = self._subtreeDelete(root.right, item)
else: # delete root
if root.left is None: # promote right subtree
root = root.right
elif root.right is None: # promote left subtree
root = root.left
else:
# root node can't be deleted, overwrite it with max of
# left subtree and delete max node from the subtree
root.item, root.left = self._subtreeDelMax(root.left)
return root
def _subtreeDelMax(self, root):
if root.right is None: # root is the max
return root.item, root.left # return max and promote left subtree
else:
# max is in right subtree, recursively find and delete it
maxVal, root.right = self._subtreeDelMax(root.right)
return maxVal, root
def height(self, root):
if root is None:
return 0
else:
return max(BST.height(root.left), BST.height(root.right)) + 1
from BinarySearchTree import BST
from TreeNode import TreeNode
tree = TreeNode(4, TreeNode(2, TreeNode(1), TreeNode(3)), TreeNode (7, TreeNode(6),TreeNode(9)))
a = BST()
a._subtreeInsert(tree, 10)
a._subtreeInsert(tree, 5)
a._subtreeDelete(tree, 9)
print("PRE-ORDER TRANSVERSE:")
print(a.preOrder(tree))
print("IN-ORDER TRANSVERSE:")
print(a.inOrder(tree))
print("POST-ORDER TRANSVERSE:")
print(a.postOrder(tree))
print("The max depth of the tree is,", a.height(tree),"nodes deep.")
print("There are,", a.treeSize(tree),"nodes in this tree.")
Does anyone see the reason why my height function isn't working properly? Thanks!
Your function height is an instance method of the class BST, you need to call it via self and not with the class BST.
So in your particular case this is:
def height(self, root):
if root is None:
return 0
else:
return max(self.height(root.left), self.height(root.right)) + 1
However, your function height actually does not rely on any data associated directly with the search tree. self is only needed to continue the recursion. Thus, you could also turn it into static method via the staticmethod decorator:
#staticmethod
def height(root):
if root is None:
return 0
else:
return max(BST.height(root.left), BST.height(root.right)) + 1
Alternatively, you could also move the function out of the BST class entirely and get rid off BST.height and just call it via height.
From the code you posted, this holds for basically all functions of the BST class. I don't really see a need for it. You may only use the TreeNode and some top-level functions (without the BST class) in your python module to modify and interact with your tree.
Related
You will be adding to the classes Node and Tree that we developed in our lectures. There are several short methods that you will have to write.
Write a method is_similar() that takes as input two binary trees and returns true if the nodes have the same key values and are arranged in the same order and false otherwise.
def is_similar (self, pNode):
Write a method print_level() that takes as input the level and prints out all the nodes at that level. If that level does not exist for that binary search tree it prints nothing. Use the convention that the root is at level 1.
def print_level (self, level):
Write a method get_height() that returns the height of a binary tree. Recall that the height of a tree is the longest path length from the root to a leaf.
def get_height (self):
Write a method num_nodes() that returns the number of nodes in the left subtree from the root and the number of nodes in the right subtree from the root and the root itself. This function will be useful to determine if the tree is balanced.
def num_nodes (self):
Input: The input will read from a file. The file will be formatted as follows:
Line 1: Several integers separated by spaces to be inserted into Tree 1
Line 2: Several integers separated by spaces to be inserted into Tree 2
You will read both lines of data. Create two Trees and insert the integers in the order given. Then you will use these two trees to test the methods that you have written.
Output: The output will be formatted as follows:
The Trees are similar: (True or False)
Levels of Tree 1:
print each level on its own line
Levels of Tree 2:
print each level on its own line
Height of Tree 1:
Nodes in Tree 1:
Height of Tree 2:
Nodes in Tree 2:
For example, given the following input file:
14 17 1
14 17 1
This would be the output:
The Trees are similare: True
Levels of Tree 1:
14
1 17
Levels of Tree 2:
14
1 17
Height of Tree 1: 1
Nodes in Tree 1: 3
Height of Tree 2: 1
Nodes in Tree 2: 3
You will be writing helper methods for the Tree class that we developed. The following is the outline of the code that you will be submitting. You may include other functions that we developed for completeness. You may add helper functions as needed.
Below is the code that I need help finishing. Not entirely sure how to start the helper functions or main so any help would be appreciated.
import os
class Node (object):
def __init__ (self, data):
self.data = data
self.lchild = None
self.rchild = None
class Tree (object):
def __init__ (self):
self.root = None
# insert data into the tree
def insert (self, data):
new_node = Node (data)
if (self.root == None):
self.root = new_node
return
else:
current = self.root
parent = self.root
while (current != None):
parent = current
if (data < current.data):
current = current.lchild
else:
current = current.rchild
# found location now insert node
if (data < parent.data):
parent.lchild = new_node
else:
parent.rchild = new_node
# Returns true if two binary trees are similar
def is_similar (self, pNode):
pass
# Prints out all nodes at the given level
def print_level (self, level):
pass
# Returns the height of the tree
def get_height (self):
pass
# Returns the number of nodes in tree which is
# equivalent to 1 + number of nodes in the left
# subtree + number of nodes in the right subtree
def num_nodes (self):
pass
def main():
# write code here
main()
As a hint, think of how you would need to traverse the binary tree in the implementation of each helper method.
For num_nodes, I am not sure what "and the number of nodes in the right subtree from the root and the root itself." means. Should we return the number of nodes in the right subtree + 1?
#classmethod
def count_below(node):
count=0
if (node == None):
return 0 # if one of the root's childs was None
if (node.lchild == None and node.rchild == None): # leaf
return 1 # base case
if (node.lchild != None):
count+=count_below(node.lchild)
if (node.rchild != None):
count+=count_below(node.rchild)
return count
def num_nodes(self):
if (self.root == None):
return 0
return count_below(self.root.lchild), count_below(self.root.rchild) + 1
#classmethod
def depth_below(node):
if node is None:
return 0 # base case
# Compute the depth of each subtree
ldepth = depth_below(node.lchild) # recurse left
rdepth = depth_below(node.rchild) # recurse right
# once all the recursive calls performed on this node's childs resolve
# return the depth of the subtree of this node with the greater depth
if (ldepth > rdepth):
return ldepth+1
else:
return rdepth+1
def get_height(self):
return depth_below(self.root) # depth from root
#classmethod
def explore_childs(node, current_level, target_level):
if (node.lchild==None and node.rchild==None):
return # base case
if (current_level == target_level):
if (node.lchild!=None):
print(node.lchild.data)
if (node.rchild!=None):
print(node.rchild.data)
return # base case
if (node.lchild!=None):
explore_childs(node.lchild, current_level+1, target_level) # recurse left
if (node.rchild!=None):
explore_childs(node.rchild, current_level+1, target_level) # recurse right
def print_level(self, level):
if (level > self.get_height()):
pass # throw error
explore_childs(root, 0, level)
I have the task to perform some basic operations on Binary Search Trees and I'm not sure what is the clever way to do it.
I know that the usual way would be to write a class for the nodes and one for the tree so that I can build up my tree from given values and perform certain tasks on it. The thing is, I'm already getting the tree as a list and since BSTs are not unique, there won't come any good from it if I take each value and build the tree myself.
So... I'm getting a list like this:
11 9 2 13 _, 4 18 2 14 _, 2 10 _ 11 4, 14 16 4 _ _, 13 0 11 _ _ | 10 | 7
which means:
key value parent left right, ... | value1 | value2
So as you see the BST is given explicitly. My tasks are to do a level-print of the tree, return the path from root to value1, do a rotate-right operation on the subtree that has value1, then delete value1 and then insert value2.
What would be an efficient way to tackle this problem?
Here is one possible way of implementing the tree. Hope it helps. Though this contains insertions and popular traversals, not rotations or deletions.
Reference: http://www.thelearningpoint.net/computer-science/learning-python-programming-and-data-structures/learning-python-programming-and-data-structures--tutorial-20--graphs-breadth-and-depth-first-search-bfsdfs-dijkstra-algorithm-topological-search
'''
Binary Search Tree is a binary tree(that is every node has two branches),
in which the values contained in the left subtree is always less than the
root of that subtree, and the values contained in the right subtree is
always greater than the value of the root of the right subtree.
For more information about binary search trees, refer to :
http://en.wikipedia.org/wiki/Binary_search_tree
'''
#Only for use in Python 2.6.0a2 and later
from __future__ import print_function
class Node:
# Constructor to initialize data
# If data is not given by user,its taken as None
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
# __str__ returns string equivalent of Object
def __str__(self):
return "Node[Data = %s]" % (self.data,)
class BinarySearchTree:
def __init__(self):
self.root = None
'''
While inserting values in a binary search tree, we first check
whether the value is greater than, lesser than or equal to the
root of the tree.
We initialize current node as the root.
If the value is greater than the current node value, then we know that
its right location will be in the right subtree. So we make the current
element as the right node.
If the value is lesser than the current node value, then we know that
its right location will be in the left subtree. So we make the current
element as the left node.
If the value is equal to the current node value, then we know that the
value is already contained in the tree and doesn't need to be reinserted.
So we break from the loop.
'''
def insert(self, val):
if (self.root == None):
self.root = Node(val)
else:
current = self.root
while 1:
if (current.data > val):
if (current.left == None):
current.left = Node(val)
break
else:
current = current.left
elif (current.data < val):
if (current.right == None):
current.right = Node(val)
break
else:
current = current.right
else:
break
'''
In preorder traversal, we first print the current element, then
move on to the left subtree and finally to the right subree.
'''
def preorder(self, node):
if (node == None):
return
else:
print(node.data, end=" ")
self.preorder(node.left)
self.preorder(node.right)
'''
In inorder traversal, we first move to the left subtree, then print
the current element and finally move to the right subtree.
'''
#Important : Inorder traversal returns the elements in sorted form.
def inorder(self, node):
if (node == None):
return
else:
self.inorder(node.left)
print(node.data, end=" ")
self.inorder(node.right)
'''
In postorder traversal, we first move to the left subtree, then to the
right subtree and finally print the current element.
'''
def postorder(self, node):
if (node == None):
return
else:
self.postorder(node.left)
self.postorder(node.right)
print(node.data, end=" ")
tree = BinarySearchTree()
tree.insert(1)
tree.insert(9)
tree.insert(4)
tree.insert(3)
tree.insert(5)
tree.insert(7)
tree.insert(10)
tree.insert(0)
print ("Preorder Printing")
tree.preorder(tree.root)
print("\n\nInorder Printing")
tree.inorder(tree.root)
print("\n\nPostOrder Printing")
tree.postorder(tree.root)
Here is the implementation of Binary Search Tree with it's basic operations like insert node, find node
class Node:
def __init__(self,data):
self.left = None
self.right = None
self.data = data
class BST:
def __init__(self):
self.root = None
def set_root(self,data):
self.root = Node(data)
def insert_node(self,data):
if self.root is None:
self.set_root(data)
else:
n = Node(data)
troot = self.root
while troot:
if data < troot.data:
if troot.left:
troot = troot.left
else:
troot.left = n
break
else:
if troot.right:
troot = troot.right
else:
troot.right = n
break
def search_node(self,data):
if self.root is None:
return "Not found"
else:
troot = self.root
while troot:
if data < troot.data:
if troot.left:
troot = troot.left
if troot.data == data:
return "Found"
else:
return "Not found"
elif data > troot.data:
if troot.right:
troot = troot.right
if troot.data == data:
return "Found"
else:
return "Not found"
else:
return "Found"
tree = BST()
tree.insert_node(10)
tree.insert_node(5)
tree.insert_node(20)
tree.insert_node(7)
print(tree.root.data)
print(tree.root.left.data)
print(tree.root.right.data)
print(tree.root.left.right.data)
print(tree.search_node(10))
print(tree.search_node(5))
print(tree.search_node(20))
print(tree.search_node(7))
print(tree.search_node(12))
print(tree.search_node(15))
Output:
10
5
20
7
Found
Found
Found
Found
Not found
Not found
In this specific case I had success using a dictionary as a datatype to store the graph. The key is the node_key and the value is a list with the attributes of the node. In this way it is rather fast to find the needed nodes and all its attributes.
I'm just not sure if there is a way to make it reasonably faster.
I'm fairly new to programming and I want to screw around with some Binary Search Trees. I want to make a function that counts the number of nodes in the tree recursively, however, when I run my function it doesn't seem to work and it keeps returning 'none' as if there is nothing in my tree. Could anyone help me find the problem here?
This is my TreeNode class:
class TreeNode(object):
def __init__(self, data = None, left=None, right=None):
self.item = data
self.left = left
self.right = right
def __str__(self):
return str(self.item)
This is my main function, I trimmed most of it down just so we can get to the problem referring to the counting of the nodes.
from TreeNode import TreeNode
class BST(object):
#------------------------------------------------------------
def __init__(self):
"""create empty binary search tree
post: empty tree created"""
self.root = None
def treeSize(self, root, size = 0):
if root is None:
return -1
if root is not None:
size += 1
if root.left is not None:
self.treeSize(root.left, size)
if root.right is not None:
self.treeSize(root.right, size)
This is the code I use to test out my function:
from BinarySearchTree import BST
from TreeNode import TreeNode
tree = TreeNode(4, TreeNode(2, TreeNode(1), TreeNode(3)), TreeNode (7, TreeNode(6),TreeNode(8)))
a = BST()
print(a.postOrder(tree))
print(a.treeSize(tree))
When I called the 'print(a.treeSize(tree))' It just returns 'none' and not '7' like it should.
You can also do it the good old recursive way:
def treeSize(self, root):
if root is None:
return 0
if root is not None:
return 1 + self.treeSize(root.left) + self.treeSize(root.right)
Jonathan's answer is nice as well.
I see. You think size is going to get updated in the called functions. It won't as it's local to each function. You could call global on it, but that's not optimal.
You could set it as a member variable (don't actually do it this way):
def __init__(self):
...
self.size = 0
def treeSize(self,...):
...
self.size += 1
...
return self.size
but the obvious bug is self.size will double every time treeSize is called. You can fix that too, but let's use patterns we know and love. Do it the good old recursive way like VHarisop wrote.
So I'm fairly new to programming and I am trying to make my delete function in my binary search tree to delete on the side that has the highest depth of nodes. However, I keep getting an error once I try to run it and I know it is a simple fix but I cannot figure it out after reading a few similar questions on here.
Here is my error I get:
C:\Python33\python.exe "C:/Users/koopt_000/Desktop/College/Sophomore Semester 2/Computer Science 231/Chapter7/Test.py"
Traceback (most recent call last):
File "C:/Users/koopt_000/Desktop/College/Sophomore Semester 2/Computer Science 231/Chapter7/Test.py", line 10, in <module>
a.delete(tree, 9)
File "C:\Users\koopt_000\Desktop\College\Sophomore Semester 2\Computer Science 231\Chapter7\BinarySearchTree.py", line 111, in delete
ldepth == max(self.height(root.left))
TypeError: 'int' object is not iterable
Process finished with exit code 1
Here are my following parts of code starting from my TreeNodes, to BST(main function), and then my test code.
class TreeNode(object):
def __init__(self, data = None, left=None, right=None):
self.item = data
self.left = left
self.right = right
def __str__(self):
return str(self.item)
from TreeNode import TreeNode
class BST(object):
#------------------------------------------------------------
def __init__(self):
"""create empty binary search tree
post: empty tree created"""
self.root = None
self.size = 0
def delete(self, root, item, ldepth = 0, rdepth = 0 ):
"""remove item from binary search tree
post: item is removed from the tree"""
if ldepth == 0:
ldepth == max(self.height(root.left))
if rdepth == 0:
rdepth == max(self.height(root.right))
if ldepth > rdepth:
depth = ldepth
print(depth)
elif ldepth < rdepth:
depth = rdepth
print(depth)
else:
depth = ldepth
print(depth)
self.root = self._subtreeDelete(root, item, depth)
#------------------------------------------------------------
def _subtreeDelete(self, root, item, depth):
if root is None: # Empty tree, nothing to do
return None
if item < root.item: # modify left
root.left = self._subtreeDelete(root.left, item)
elif item > root.item: # modify right
root.right = self._subtreeDelete(root.right, item)
else: # delete root
if root.left is None: # promote right subtree
root = root.right
elif root.right is None: # promote left subtree
root = root.left
else:
# root node can't be deleted, overwrite it with max of
# left subtree and delete max node from the subtree
root.item, root.left = self._subtreeDelMax(root.left)
return root
#------------------------------------------------------------
def _subtreeDelMax(self, root):
if root.right is None: # root is the max
return root.item, root.left # return max and promote left subtree
else:
# max is in right subtree, recursively find and delete it
maxVal, root.right = self._subtreeDelMax(root.right)
return maxVal, root
def height(self, root):
if root is None:
return 0
else:
return max(self.height(root.left), self.height(root.right)) + 1
from BinarySearchTree import BST
from TreeNode import TreeNode
tree = TreeNode(4, TreeNode(2, TreeNode(1), TreeNode(3)), TreeNode (7, TreeNode(6),TreeNode(9)))
a = BST()
a._subtreeInsert(tree, 10)
a._subtreeInsert(tree, 5)
a.delete(tree, 9)
print("PRE-ORDER TRANSVERSE:")
print(a.preOrder(tree))
print("IN-ORDER TRANSVERSE:")
print(a.inOrder(tree))
print("POST-ORDER TRANSVERSE:")
print(a.postOrder(tree))
print("The max depth of the tree is,", a.height(tree),"nodes deep.")
print("There are,", a.treeSize(tree),"nodes in this tree.")
Could anyone tell me whats wrong? I need this to work in order to make my delete function work properly,
The max() function in python takes an iterable object, like a list, in which it can iterates over to find the max value.
self.height(root.left)
is a single int, essentially a single value which is not iteratable, which is throwing your error.
I've created a BST. and now I want to find the height of the BST developed.
Here is my code for constructing the BST
class Node:
'''represents a new node in the BST'''
def __init__(self,key):
self.key=key
self.disconnect()
def disconnect(self):
self.left=None;
self.right=None;
self.parent=None;
def __str__(self):
return 'node with kay %s'%self.key
class BST:
def __init__(self):
self.root=None
def insert(self,t):
'''inserts a new element into the tree'''
if self.root is None:
self.root = Node(t)
else:
self._do_insert(self.root,t)
def _do_insert(self,parent,t):
if t > parent.key:
if parent.left is None:
parent.left = Node(t)
else:
self._do_insert(parent.left,t)
elif t < parent.key:
if parent.right is None:
parent.right = Node(t)
else:
self._do_insert(parent.right,t)
else:
# raise a KeyError or something appropriate?
pass
I've a list of numbers ([2,4,6,3,190,1,56 and so on]) via which this BST is constructed.
Now I want to find the height of the BST created. How can I do that?
EDIT
As per the solution provided I tried this :-
def create_bst(values):
'''Creates a BST and returns the BST created object'''
BSTobj = BST()
for i in values:
BSTobj.insert(i)
return BSTobj
def height_of_BST(bst):
'''Returns the height of the BST created'''
if bst == None: return 0
else: return 1 + max(height_of_BST(bst.left), height_of_BST(bst.right))
print height_of_BST(create_bst(unique_values))
And its not working. It pops up an error saying BST instance has no attribute 'left'
The height of a nonempty binary search tree is 1 + the height of its tallest subtree, or just 1 if it has no children. This translates pretty directly to a recursive algorithm. In pseudocode:
def height(bst):
if isempty(bst):
return 0
else:
return 1 + max(height(bst.left), height(bst.right))
The BST in your class is actually stored in BST.root not in BST. You need to modify your code to look at BST.root instead of BST.
Try:
def height(BST):
return actual_height(BST.root)
def actual_height(bst_node):
if bst_node is None:
return 0
else:
return 1 + max(actual_height(bst_node.left), actual_height(bst_node.right))
This defines a helper function that does the actual work but lets you just call height on the BST object. In the future, you might just want to only have a Node class because your BST class is basically just a wrapper around the root value.
The interpreter is complaining because you didn't check for cases where the node has no children. If a node has no children it heigth is -1
here a solution
def height(bst):
if bst == None :
return -1
else:
return 1 + max(height(bst.left), height(bst.right))
You can use hasattr to check if the object has the attr, if not you get to the end of the tree
def height(bst_node):
if not hasattr(bst_node, 'left') or not hasattr(bst_node, 'right'):
return 0
else:
return 1 + max(height(bst_node.left), height(bst_node.right))