python binary tree traversal with search and delete functions - python

I create a binary tree traversal project. Unfortunately, I have a basic knowledge of python. I wrote "preorder", "inorder" and "postorder" correctly. But I can not create find and delete node function. please help.
Please check the code below. Please help to create those 2 functions.
Thank you
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def find(self, value):
if self.value == value:
return True
elif value < self.value and self.left:
return self.left.find(value)
elif value > self.value and self.right:
return self.right.find(value)
return False
class BinaryTree(object):
def __init__(self, root):
self.root = Node(root)
def print_tree(self, traversal_type):
if traversal_type == "preorder":
return self.preorder_print(tree.root, "")
elif traversal_type == "inorder":
return self.inorder_print(tree.root, "")
elif traversal_type == "postorder":
return self.postorder_print(tree.root, "")
else:
print("Traversal type "+str(traversal_type)+" is not supported.")
def preorder_print(self, start, traversal):
# Root->Left->Right
if start:
traversal += (str(start.value)+"-")
traversal = self.preorder_print(start.left, traversal)
traversal = self.preorder_print(start.right, traversal)
return traversal
def inorder_print(self, start, traversal):
# Left->Root->Right
if start:
traversal = self.inorder_print(start.left, traversal)
traversal += (str(start.value) + "-")
traversal = self.inorder_print(start.right, traversal)
return traversal
def postorder_print(self, start, traversal):
# Left->Right->Root
if start:
traversal = self.postorder_print(start.left, traversal)
traversal = self.postorder_print(start.right, traversal)
traversal += (str(start.value) + "-")
return traversal
# Set up tree order
tree = BinaryTree(1)
tree.root.left = Node(2)
tree.root.right = Node(3)
tree.root.left.left = Node(4)
tree.root.left.right = Node(5)
tree.root.right.left = Node(6)
tree.root.right.right = Node(7)
print("Preorder: " + tree.print_tree("preorder")) # 1-2-4-5-3-6-7
print("Inorder: " + tree.print_tree("inorder")) # 4-2-5-1-6-3-7
print("Postorder: " + tree.print_tree("postorder")) # 4-2-5-6-3-7-1
print(tree.root.find(1))
print(tree.root.find(2))
print(tree.root.find(3))
print(tree.root.find(4))
print(tree.root.find(5))
print(tree.root.find(6))
print(tree.root.find(7))
print(tree.root.find(8)) ```

The reason find is not working is the tree you have setup is not a binary search tree. In a BST all nodes to the left have values lower than the root and all nodes to the right have higher values. Check the tree you have constructed.
Here is the implementation for delete node.
https://www.geeksforgeeks.org/binary-search-tree-set-2-delete/

Related

Python Expression Tree only able to contain three values

For the following code, a prefix expression is turned into an expression tree in python.
I am trying to turn a prefix expression into an inflix expression by traversing the expression tree from left to right. The code works if there are only three values in the expression (i.e. "+ 1 2"). But the output list won't contain anymore than three items.
Any hint would be highly appreciated!
ops = ['+','-','*','/']
class BinaryTreeNode:
#def __init__(self, value, left=None, right=None):
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
def __str__(self):
return str(self.value)
class BinarySearchTree:
def __init__(self):
self.root = None
def __str__(self):
return str(self.value)
def add(self,value):
if self.root is None:
self.root = BinaryTreeNode(value)
else:
#pointer set at root if root not empty
ptr = self.root
while True:
if value in ops:
ptr = self.root
#if left of pointer is empty, add new Node
if ptr.left is None:
ptr.left = BinaryTreeNode(value)
break
#set pointer to new Node
ptr = ptr.left
#left of pointer is not empty, add right node
else:
# return pointer to root
#ptr = self.root
ptr.right = BinaryTreeNode(value)
break
# reset pointer to new Node
ptr = ptr.right
#if value not in ops
else:
if ptr.left is None:
ptr.left = BinaryTreeNode(value)
ptr = ptr.left
break
else:
ptr.right = BinaryTreeNode(value)
ptr = ptr.right
break
def in_order(self):
def traverse(node):
if node.left is not None:
yield from traverse(node.left)
yield node.value
if node.right is not None:
yield from traverse(node.right)
return traverse(self.root)
exp = "+ 1 2"
split = exp.split()
bst = BinarySearchTree()
for i in split:
bst.add(i)
print(list(bst.in_order()))
input: "+ 1 2"
output: [1, +, 2]
good
input: "+ / 1 2 * 3 4"
output: [/, +, 4]
what happened?? :-(
Thanks for your time!!

How can I find the depth of a specific node inside a binary tree?

I'm trying to figure out a recursive solution to this problem. The main thing is to return the level in the binary tree where the node is.
def find_depth(tree, node):
if node == None:
return 0
else:
return max(find_depth(tree.left))
#recursive solution here
Using this class for the values:
class Tree:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
Example: Calling find_depth(tree, 7) should return the level where 7 is in the tree. (level 2)
3
/ \
7 1 <------ return that 7 is at level 2
/ \
9 3
maybe this is what you are looking for
def find_depth(tree, node):
if node is None or tree is None:
return 0
if tree == node:
return 1
left = find_depth(tree.left, node)
if left != 0:
return 1 + left
right = find_depth(tree.right, node)
if right != 0:
return 1 + right
return 0
You need to provide information about depth in find_depth call. It might look like this (assuming 0 is a sentinel informing that node is not found):
def find_depth(tree, node, depth=1):
if node == None:
return 0
if tree.value == node:
return depth
left_depth = find_depth(tree.left, node, depth+1)
right_depth = find_depth(tree.right, node, depth+1)
return max(left_depth, right_depth)
Then you call it with two parameters: x = find_depth(tree, 7).
Recursion is a functional heritage and so using it with functional style yields the best results -
base case: if the input tree is empty, we cannot search, return None result
inductive, the input tree is not empty. if tree.data matches the search value, return the current depth, d
inductive, the input tree is not empty and tree.data does not match. return the recursive result of tree.left or the recursive result of find.right
def find (t = None, value = None, d = 1):
if not t:
return None # 1
elif t.value == value:
return d # 2
else:
return find(t.left, value, d + 1) or find(t.right, value, d + 1) # 3
class tree:
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
t = tree \
( 3
, tree(7, tree(9), tree(3))
, tree(1)
)
print(find(t, 7)) # 2
print(find(t, 99)) # None
You can implement the find method in your tree class too
def find (t = None, value = None, d = 1):
# ...
class tree
def __init__ #...
def find(self, value)
return find(self, value)
print(t.find(7)) # 2
print(t.find(99)) # None

Binary Search Tree - finding height and depth

This is my first time coding binary search tree.
I reference alot from online, and tried some of their code.
Was wondering
why this 2 code isn't working and gave me the same error, when I'm trying to print it out
def height(self,node):
if node is None:
return 0
else:
return max(height(node.left), height(node.right)) + 1
def depth(self, count=0):
if self.root is None:
return count
return max(depth(self.root.left, count+1),
depth(self.root.right, count+1))
both have the same error which says
"global name height is not define"
"global name depth is not define"
I wonder why, because I'm calling the same function
complete code:
class BST:
root=None
def put(self, key, val):
self.root = self.put2(self.root, key, val)
def put2(self, node, key, val):
if node is None:
#key is not in tree, create node and return node to parent
return Node(key, val)
if key < node.key:
# key is in left subtree
node.left = self.put2(node.left, key, val)
elif key > node.key:
# key is in right subtree
node.right = self.put2(node.right, key, val)
else:
node.val = val
# node.count = 1 + self.size2(node.left) + self.size2(node.right)
return node
# draw the graph
def drawTree(self, filename):
# create an empty undirected graph
G=pgv.AGraph('graph myGraph {}')
# create queue for breadth first search
q = deque([self.root])
# breadth first search traversal of the tree
while len(q) <> 0:
node = q.popleft()
G.add_node(node, label=node.key+":"+str(node.val))
if node.left is not None:
# draw the left node and edge
G.add_node(node.left, label=node.left.key+":"+str(node.left.val))
G.add_edge(node, node.left)
q.append(node.left)
if node.right is not None:
# draw the right node and edge
G.add_node(node.right, label=node.right.key+":"+str(node.right.val))
G.add_edge(node, node.right)
q.append(node.right)
# render graph into PNG file
G.draw(filename,prog='dot')
os.startfile(filename)
def createTree(self):
self.put("F",6)
self.put("D",4)
self.put("C",3)
self.put("B",2)
self.put("A",1)
self.put("E",5)
self.put("I",9)
self.put("G",7)
self.put("H",8)
self.put("J",10)
def height(self,node):
if node is None:
return 0
else:
return max(height(node.left), height(node.right)) + 1
def depth(self, count=0):
if self.root is None:
return count
return max(depth(self.root.left, count+1),
depth(self.root.right, count+1))
class Node:
left = None
right = None
key = 0
val = 0
def __init__(self, key, val):
self.key = key
self.val = val
bst = BST()
bst.createTree()
bst.drawTree("demo.png")
print bst.get("B")
##print bst.size("D")
##print bst.size("F")
print bst.depth("B")
Python doesn't scope code to the local class automatically :
return max(self.height(node.left), self.height(node.right)) + 1
and
return max(self.depth(self.root.left, count+1),
self.depth(self.root.right, count+1))
Are you sure that your BST.height() and BST.depth() methods are really in the scope of BST? It looks like they are not indented into the BST class. Check your spacing.

Find number of elements smaller than a given element in BST

I have been struggling with this problem for a while and I am a Python beginner when it comes to BST, so I would appreciate some help. I am dynamically adding elements from an (unsorted) array into BST. That part is fine, I know how to do that. The next step, proved to be impossible with my current skill set. As I am adding elements to the tree, I need to be able to find current rank of any element in the tree. I know there are subtleties in this problem, so I would need help to at least find the number of nodes that are below the given node in BST. For example, in this case, node 15 has nodes 10,5 and 13 below it, so the function will return 3. Here is my existing code [this is a problem from Cracking the coding interview, chapter 11]
class Node:
"""docstring for Node"""
def __init__(self, data):
self.data = data
self.left=None
self.right=None
self.numLeftChildren=0
self.numRightChildren=0
class BSTree:
def __init__(self):
self.root = None
def addNode(self, data):
return Node(data)
def insert(self, root, data):
if root == None:
return self.addNode(data)
else:
if data <= root.data:
root.numLeftChildren+=1
root.left = self.insert(root.left, data)
else:
root.numRightChildren+=1
root.right = self.insert(root.right, data)
return root
def getRankOfNumber(self,root,x):
if root==None:
return 0
else:
if x>root.data :
return self.getRankOfNumber(root.right,x)+root.numLeftChildren+1
elif root.data==x:
return root.numLeftChildren
else:
return self.getRankOfNumber(root.left,x)
BTree=BSTree()
root=BTree.addNode(20)
BTree.insert(root,25)
BTree.insert(root,15)
BTree.insert(root,10)
BTree.insert(root,5)
BTree.insert(root,13)
BTree.insert(root,23)
You can go by this approach:
1. Have 2 more fields in each node numLeftChildren and numRightChildren.
2. Initialize both of them to 0 when you create a new node.
3. At the time of insertion, you make a comparison if the newly added node's
key is less than root's key than you increment, root's numLeftChildren and
call recursion on root's left child with the new node.
4. Do Same thing if new node's key is greater than root's key.
Now, come back to your original problem, You have to find out the number of children in left subtree. Just find out that node in O(logN) time and just print the numLeftChildren
Time Complexity: O(logN)
PS: I have added another field numRightChildren which you can remove if you are always interested in knowing the number of nodes in left subtree only.
You could modify your BST to contain the number of nodes beneath each node.
Or you could iterate over a traditional BST from least to greatest, counting as you go, and stop counting when you find a node of the required value.
You could simplify the code by using just instances of the Node class, as your BSTree instance operates on the root node anyway. Another optimization could be to not represent duplicate values as separate nodes, but instead use a counter of occurrences of the key:
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
self.num_left_children = 0
self.occurrences = 1
def insert(self, data):
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
self.num_left_children += 1
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.occurrences += 1
def get_rank(self, data):
if data < self.data:
return self.left.get_rank(data)
elif data > self.data:
return (self.occurrences + self.num_left_children +
self.right.get_rank(data))
else:
return self.num_left_children
Demo:
root = Node(20)
root.insert(25)
root.insert(15)
root.insert(10)
root.insert(10)
root.insert(5)
root.insert(13)
root.insert(23)
print(root.get_rank(15)) # 4
You can use the below function to find the number of the nodes in the tree (including the root).
def countNodes(self, root):
if root == None:
return 0
else
return (1 + countNodes(root.left) + countNodes(root.right));
To find the number of nodes that lie below root, subtract 1 from the value returned by the function. I think this will help get you started on the problem.
Your code will look like:
class Node:
"""docstring for Node"""
def init(self, data):
self.data = data
self.left=None
self.right=None
self.depth=0
class BSTree:
def init(self):
self.root = None
def addNode(self, data):
return Node(data)
def insert(self, root, data):
if root == None:
return self.addNode(data)
else:
if data <= root.data:
root.left = self.insert(root.left, data)
else:
root.right = self.insert(root.right, data)
return root
BTree=BSTree()
root=BTree.addNode(20)
BTree.insert(root,25)
BTree.insert(root,15)
BTree.insert(root,10)
BTree.insert(root,5)
BTree.insert(root,13)
BTree.insert(root,23)
BTree.insert(root,23)
numLeft = countNodes(root->left);
numRight = countNodes(root->right);
numChildren = numLeft + numRight;

how to find the height of a node in binary tree recursively

path = 0 # the lenght of the path
while self.right != None or self.left != None:
while self.right != None:
self = self.right
path = path +1
while self.left != None:
self = self.left
path = path +1
return path
this is my sample code for find the Height, is defined as the length of the
longest path by number of nodes from self to a leaf. The height of a leaf node is 1.
it doesn't work.
What you're doing isn't recursive, it's iterative.
Recursive would be something like:
def height(node):
if node is None:
return 0
else:
return max(height(node.left), height(node.right)) + 1
You were given the solution by mata, but I suggest you also look at your code and understand what it is doing:
while self.right != None:
self = self.right
path = path +1
What will this do? it will find the right child, then its right child, and so on. So this checks only one path of the "rightmost" leaf.
This does the same for the left:
while self.left != None:
self = self.left
path = path +1
The idea in recursion is that for each subproblem, you solve it using the exact same recipe for all other subproblems. So if you would apply your algorithm only to a subtree or a leaf, it would still work.
Also, a recursive definition calls itself (although you can implement this with a loop, but that is beyond the scope here).
Remeber the definition:
Recursion: see definition of Recursion.
;)
def height(node):
if node is None:
return 0
else:
if node.left==None and node.right==None:
return max(height(node.left), height(node.right))+0
else:
return max(height(node.left), height(node.right))+1
If you consider each increasing edge to be the height.
To pass hackerrank testcases
def getHeight(self, root):
if root == None:
return -1
else:
return 1 + max( self.getHeight(root.left), self.getHeight(root.right) )
Here is the complete program in Python ::
class Node :
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def maxDepth(node):
if node is None :
return 0
else :
ldepth = maxDepth(node.left)
rdepth = maxDepth(node.right)
if (ldepth>rdepth):
return ldepth +1
else :
return rdepth +1
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
print "Height of tree is %d" %(maxDepth(root))
Source : here
def height(self):
if self.root !=None:
return self._height(self.root,0)
else:
return 0
def _height(self,cur_node,cur_height):
if cur_node==None :
return cur_height
left_height = self._height(cur_node.left_child,cur_height+1)
right_height = self._height(cur_node.right_child,cur_height+1)
return max(left_height,right_height)

Categories

Resources