How to check if a Binary tree is full? - python

Student here. I have coded a method to add to a BinaryTree class that checks to see if the binary tree is full (the rest of the class code came from a Python textbook). I believe it is working as it should but am new to coding and I do not know how to check without the visual of the tree to see if all of the leaves are on the same level. Can anyone take a look at the is isFullBinaryTree(self) method is correct? It is near the end of the class. The test program seems to be working, but I am not positive.
My thought was that if I coded a count variable for each side of the tree and if the count is the same on both sides, then the leaves must all be on the same level which would make it a full tree.
Here is the full code:
class TreeNode:
def __init__(self, e):
self.element = e
self.left = None # Point to the left node, default None
self.right = None # Point to the right node, default None
class BinaryTree:
def __init__(self):
self.root = None
self.size = 0
# Insert element e into the binary search tree
# Return True if the element is inserted successfully
def insert(self, e):
if self.root == None:
self.root = self.createNewNode(e) # Create a new root/Create the node for e as the root
else:
# Locate the parent node
parent = None
current = self.root
while current != None:
if e < current.element:
parent = current # Keep the parent
current = current.left # Go left
elif e > current.element:
parent = current # Keep the parent
current = current.right # Go right
else:
return False # Duplicate node not inserted
# Create a new node for e and attach it to parent
if e < parent.element:
parent.left = self.createNewNode(e)
else:
parent.right = self.createNewNode(e)
self.size += 1 # Increase tree size
return True # Element inserted
# Create a new TreeNode for element e
def createNewNode(self, e):
return TreeNode(e)
# Returns true if the tree is a full binary tree
def isFullBinaryTree(self):
current = self.root # Start from the root
while current != None:
leftNode = current.left
rightNode = current.right
leftCount = 0
rightCount = 0
while leftNode != None:
current = leftNode
leftNode = current.left
leftCount += 1 # add 1 because we are moving from current one time
while rightNode != None:
current = rightNode
rightNode = current.right
rightCount += 1 # add 1 because we are moving from current one time
if leftCount == rightCount:
return True
else:
return False
return False
def main():
numbers = [2, 4, 3, 1, 8, 5, 6, 7, 0]
intTree1 = BinaryTree()
for e in numbers:
intTree1.insert(e)
print("\nIs intTree1 full? ", end = "")
print(intTree1.isFullBinaryTree())
numbers2 = [2, 4, 3, 1, 8, 5, 6, 7]
intTree2 = BinaryTree()
for e in numbers2:
intTree2.insert(e)
print("\nIs intTree2 full? ", end = "")
print(intTree2.isFullBinaryTree())
main()

If your tree looked like /\, then I think it would return True because you're only iterating the outside of the tree, not checking the fullness of the inner branches
Instead of looping at all, or even counting, I would suggest recursion
You'll need to implement the isFullBinaryTree methods on the TreeNode class for this to work, though.
class TreeNode:
def __init__(self, e):
self.element = e
self.left = None # Point to the left node, default None
self.right = None # Point to the right node, default None
def isFullBinaryTree(self):
# check if we are a leaf
if self.left is None and self.right is None:
return True
# recursively check the left fullness
full_left = self.left.isFullBinaryTree() if self.left else False
# recursively check the right fullness
full_right = self.right.isFullBinaryTree() if self.right else False
# return True if checked that both left and right are full
return full_left and full_right
Once you do this, then the BinaryTree class can simply be checking if the root exists and if the root TreeNode is considered full itself.
e.g.
def isFullBinaryTree(self):
return self.root.isFullBinaryTree() if self.root else False

Related

Trouble balancing a binary search tree using AVL

I'm unable to identify where I'm going wrong with my AVL implementation for balancing an existing binary search tree. I'm not getting any errors but my binary search tree does not come out to be properly balanced. After insertion, my binary search tree looks like (it would be prudent here to mention that my display_keys method gives us a visualization that is rotated by 90 degrees):
∅
The-Dreamers
∅
Saint-Laurent
∅
Pierrot-le-Fou
∅
Contempt
Cold-War
Before-Sunrise
∅
Basic-Instinct
∅
This is correct as it seems be to be following the rules for a BST.
But after calling the BalanceTree() method on my binary search tree, I seem to get:
∅
The-Dreamers
Saint-Laurent
Pierrot-le-Fou
Contempt
Cold-War
Before-Sunrise
Basic-Instinct
∅
which as you can see, is not Balanced. But wait, and here's the catch, if I call BalanceTree() again, the tree comes out to be perfectly balanced and isBSTBalanced returns True also. After the second call to BalanceTree(), our tree looks like:
∅
The-Dreamers
Saint-Laurent
Pierrot-le-Fou
Contempt
Cold-War
Before-Sunrise
Basic-Instinct
∅
I am adding the complete source code for my BST class for clarity and if somebody wants to execute the code, but I have added a comment (#Addition of new methods for AVL starts here) in the BST class to indicate where the methods for AVL start. You need only concern yourself with them. I would like for you help me pinpoint what exactly is going wrong in my code.
class BST:
class TreeNode:
def __init__(self, key, value, left=None, right=None, parent=None):
self.key = key
self.value = value
self.left = left
self.right = right
self.parent = parent
self.height = 1
def __init__(self):
self.root = None
self.size = 0
def __len__(self):
return self.size
def insert(self, key, value):
if self.root == None:
self.root = self.TreeNode(key, value)
else:
self._insert(key, value, self.root)
self.size += 1
def _insert(self, key, value, curr_node):
if key < curr_node.key:
if curr_node.left is not None:
self._insert(key, value, curr_node.left)
else:
curr_node.left = self.TreeNode(key, value, parent=curr_node)
elif key > curr_node.key:
if curr_node.right is not None:
self._insert(key, value, curr_node.right)
else:
curr_node.right = self.TreeNode(key, value, parent=curr_node)
def search(self, key):
if self.root:
found = self._search(key, self.root)
if found:
return found.value
else:
return None
else:
return None
def _search(self, key, curr_node):
if not curr_node:
return None
elif curr_node.key == key:
return curr_node
elif key < curr_node.key:
return self._search(key, curr_node.left)
else:
return self._search(key, curr_node.right)
def find_min(self):
curr = self.root
while curr.left is not None:
curr = curr.left
return curr
def find(self, node):
curr = node
while curr.left is not None:
curr = curr.left
return curr
def delete(self, key):
node_to_remove = self._search(key, self.root)
if node_to_remove.left is None and node_to_remove.right is None:
#Then we identify this as a leaf node
if node_to_remove is node_to_remove.parent.left:
#Setting the parent's reference to this to None
node_to_remove.parent.left = None
elif node_to_remove is node_to_remove.parent.right:
node_to_remove.parent.right = None
#2nd Case --> Two child
elif node_to_remove.left and node_to_remove.right:
minimum = self.find(node_to_remove.right)
self.delete(minimum.key) #We will still have a ref to this node afterwards
node_to_remove.key, node_to_remove.value = minimum.key, minimum.value
#3rd Case -> One child
else:
if node_to_remove.left:
node_to_remove.left.parent = node_to_remove.parent
node_to_remove.parent.left = node_to_remove.left
elif node_to_remove.right:
node_to_remove.right.parent = node_to_remove.parent
node_to_remove.parent.right = node_to_remove.right
def traversal(self, root):
res = []
if root:
res = self.traversal(root.left)
res.append(root)
res = res + self.traversal(root.right)
return res
def inorder_traversal(self, root):
if root:
self.inorder_traversal(root.left)
print(root.key)
self.inorder_traversal(root.right)
#Addition of new methods for AVL starts here
def display_keys(self, node, space='\t', level=0):
"""
Allows us to visualize the tree (albiet rotated by 90 degrees)
"""
# print(node.key if node else None, level)
# If the node is empty
if node is None:
print(space*level + '∅')
return
# If the node is a leaf
if node.left is None and node.right is None:
print(space*level + str(node.key))
return
# If the node has children
self.display_keys(node.right, space, level+1)
print(space*level + str(node.key))
self.display_keys(node.left,space, level+1)
def height(self):
return self._height(self.root)
def _height(self, curr_node):
if curr_node is None:
return -1 #since we are counting number of edges, we will return -1
else:
return 1 + max(self._height(curr_node.left), self._height(curr_node.right))
def isBSTBalanced(self):
return self._isBSTBalanced(self.root)
def _isBSTBalanced(self, curr_node):
if curr_node is None:
return True
hleft_subtree = self._height(curr_node.left)
hright_subtree = self._height(curr_node.right)
if hleft_subtree - hright_subtree in [-1,0,1]:
return self._isBSTBalanced(curr_node.left) and self._isBSTBalanced(curr_node.right)
else:
return False
def balance_factor(self):
if self.root is not None:
return self._balance_factor(self.root)
else:
return 0
def _balance_factor(self, curr_node):
if curr_node is None:
return
hleft_subtree = self._height(curr_node.left)
hright_subtree = self._height(curr_node.right)
b_factor = hleft_subtree - hright_subtree
return b_factor
def BalanceTree(self):
if self.isBSTBalanced() == False:
return self._rebalance(self.root)
def _rebalance(self, curr_node):
if curr_node is None:
return None
curr_node.left = self._rebalance(curr_node.left)
curr_node.right = self._rebalance(curr_node.right)
curr_node.height = 1 + max(self._height(curr_node.left), self._height(curr_node.right))
#print(curr_node.height)
if self._balance_factor(curr_node) > 1 and self._balance_factor(curr_node.left) >= 0:
#left heavy subtree
return self._rotate_right(curr_node)
if self._balance_factor(curr_node) < -1 and self._balance_factor(curr_node.right) <= 0:
#right heavy subtree
return self._rotate_left(curr_node)
if self._balance_factor(curr_node) < 0 and self._balance_factor(curr_node.right) > 0:
self._rotate_right(curr_node.right)
return self._rotate_left(curr_node)
if self._balance_factor(curr_node) > 0 and self._balance_factor(curr_node.left) < 0:
self._rotate_left(curr_node.left)
return self._rotate_right(curr_node)
return curr_node
def _rotate_left(self, oldRoot):
newRoot = oldRoot.right #the newRoot is the right child of the previous root
oldRoot.right = newRoot.left #replacing right child of the old root with the left child of the new
if newRoot.left is not None:
newRoot.left.parent = oldRoot
newRoot.parent = oldRoot.parent
if oldRoot == self.root:
self.root = newRoot
else:
if oldRoot.parent.left is oldRoot: #Checking isLeftChild
oldRoot.parent.left = newRoot
else:
oldRoot.parent.right = newRoot
newRoot.left = oldRoot
oldRoot.parent = newRoot
oldRoot.height = 1 + max(self._height(oldRoot.left), self._height(oldRoot.right))
newRoot.height = 1 + max(self._height(newRoot.left), self._height(newRoot.right))
return newRoot
def _rotate_right(self, oldRoot):
newRoot = oldRoot.left #the newRoot is the left child of the previous root
oldRoot.left = newRoot.right #replacing left child of the old root with the right child of the new
if newRoot.right is not None:
newRoot.right.parent = oldRoot
newRoot.parent = oldRoot.parent
if oldRoot == self.root:
self.root = newRoot
else:
if oldRoot.parent.right is oldRoot: #Checking isRightChild
oldRoot.parent.right = newRoot
else:
oldRoot.parent.left = newRoot
newRoot.right = oldRoot
oldRoot.parent = newRoot
oldRoot.height = 1 + max(self._height(oldRoot.left), self._height(oldRoot.right))
newRoot.height = 1 + max(self._height(newRoot.left), self._height(newRoot.right))
return newRoot
if __name__ == '__main__':
obj = BST()
obj.insert('Basic-Instinct', 0)
obj.insert('The-Dreamers', 1)
obj.insert('Saint-Laurent', 2)
obj.insert('Pierrot-le-Fou', 3)
obj.insert('Contempt', 4)
obj.insert('Before-Sunrise', 5)
obj.insert('Cold-War', 8)
obj.display_keys(obj.root) #displays a visual representation of our tree, albeit rotated by 90 degrees
print()
print("isBSTBalanced:", obj.isBSTBalanced())
obj.BalanceTree()
print("isBSTBalanced:", obj.isBSTBalanced()) #After executing BalanceTree(), isBSTBalanced still returns False
print()
obj.display_keys(obj.root)
Progress: Revamped _isBSTBalanced method so that it visits every node recursively and not just the root node. The final outcome, however, remains the same.
Progress: I was able to identify one of the major issues being that while I was calling _rotate_left and _rotate_right methods in the _rebalance method, I was not returning them. In addition to this, I was not recursively visiting the left and right subtrees of curr_node, which was initially set to the root of the tree, to be able to traverse the tree in a bottom up manner. I have resolved this too. I have added a display_keys method which allows us to visualize the tree, albeit rotated by 90 degrees. I'm updating the code and prompt in this post accordingly. The problem that still remains is that I have to call the BalanceTree() method more than once in some cases for isBSTBalanced to return True.

Binary Tree for Python, getRoot does not return root

I been looking over this Binary Tree code to figure out what it does:
class BinaryTree:
def __init__(self):
self.root = None
self.size = 0
# Insert element e into the binary search tree
# Return True if the element is inserted successfully
def insert(self, e):
if self.root == None:
self.root = self.createNewNode(e) # Create a new root
else:
# Locate the parent node
parent = None
current = self.root
while current != None:
if e < current.element:
parent = current
current = current.left
elif e > current.element:
parent = current
current = current.right
else:
return False # Duplicate node not inserted
# Create the new node and attach it to the parent node
if e < parent.element:
parent.left = self.createNewNode(e)
else:
parent.right = self.createNewNode(e)
self.size += 1 # Increase tree size
return True # Element inserted
# Create a new TreeNode for element e
def createNewNode(self, e):
return TreeNode(e)
# Return the size of the tree
def getSize(self):
return self.size
# Return true if the tree is empty
def isEmpty(self):
return self.size == 0
# Remove all elements from the tree
def clear(self):
self.root == None
self.size == 0
# Return the root of the tree
def getRoot(self):
return self.root
class TreeNode:
def __init__(self, e):
self.element = e
self.left = None # Point to the left node, default None
self.right = None # Point to the right node, default None
If I do the following code:
tree = BinaryTree()
tree.insert("500")
print(tree.getRoot)
print(tree.getRoot())
Result:
<bound method BinaryTree.getRoot of <__main__.BinaryTree object at 0x036E1E68>>
<__main__.TreeNode object at 0x036FA1F0>
I would not get the string "500" back even though its the root. Is there something missing from the getRoot function? I cannot find what is making the function being unable to return the string.
tree.getRoot is a method of the BinaryTree object.
And tree.getRoot() is calling the method and it returns a TreeNode object. If you want to get "500", you should get the element property of it.
So you can try the following code:
tree = BinaryTree()
tree.insert("500")
print(tree.getRoot().element)
which prints
500

Deleting leftmost leaf in a binary tree

I wish to delete the leftmost leaf in a BT( not BST!). I tried to delete it using Reverse level order traversal but once I find the leftmost node and delete it and try returning, I cannot handle the extra recursive calls. Basically with the current code, my entire tree gets deleted recursively, but I just want it to delete leftmost leaf.
I tried breaking the recursion using exit() and my entire program stopped.
On first call only 5 should be deleted. On next call 25 should be deleted . On next call 66 should be deleted.( basically swimming up)
This is what my code looks like:
def del_leaf(node):
if(root==None):
return
if root:
# First recur on left child
del_leaf(root.left)
# the recur on right child
del_leaf(root.right)
# now print the data of node
if ( (root.isvisited == False)):
root.isvisited = True
root.left = None
root.right = None
return
The function needs a return value, something that tells the caller:
this node does not exist
this node is childless so you can delete it
OK, we're done.
So, something like
def del_leaf(node):
if(root==None):
return 1
left = del_leaf(root.left)
if (left == 2):
root.left = None
return 3
if (left == 3):
return 3
right = del_leaf(root.right)
if (right == 2):
root.right = None
return 3
if (right == 3):
return 3
return 2
I haven't tested it; that's left as an exercise for you. Also left:
better enum names than 1, 2, and 3
support for an arbitrary number of child nodes
support for an ordering function
I have modified the program that does not use recursion to:
Not rely on garbage collection to print out when a node has been removed.
Build the entire tree as presented by the OP.
Note: When the program descends down the left subtree and finds that the leftmost leaf has a right subtree, it removes this subtree. This program does not descend down the right subtree to delete the leftmost leaf of that subtree. The second algorthm does. Take your pick.
class Node:
def __init__(self, value):
self.value = value
# build tree
root = Node(90)
# left subtree:
node_50 = Node(50)
node_20 = Node(20)
node_75 = Node(75)
node_5 = Node(5)
node_5.left = None
node_5.right = None
node_25 = Node(25)
node_25.left = None
node_25.right = None
node_66 = Node(66)
node_66.left = None
node_66.right = None
node_80 = Node(80)
node_80.left = None
node_80.right = None
root.left = node_50
node_50.left = node_20
node_50.right = node_75
node_20.left = node_5
node_20.right = node_25
node_75.left = node_66
node_75.right = node_80
# right subtree:
node_150 = Node(150)
node_95 = Node(95)
node_175 = Node(175)
node_92 = Node(92)
node_92.left = None
node_92.right = None
node_111 = Node(111)
node_111.left = None
node_111.right = None
node_166 = Node(166)
node_166.left = None
node_166.right = None
node_200 = Node(200)
node_200.left = None
node_200.right = None
root.right = node_150
node_150.left = node_95
node_150.right = node_175
node_95.left = node_92
node_95.right = node_111
node_175.left = node_166
node_175.right = node_200
def del_leftmost_leaf(root):
if root.left is None and root.right is None:
print(f'Removing {root.value}')
return None # root has changed to None
parent = root
if root.left is None:
node = root.right
else:
node = root.left
while node.left:
parent = node
node = node.left
if node.right is None:
print(f'Removing {node.value}')
if parent.left is None:
parent.right = None
else:
parent.left = None
else:
print(f'Removing {node.right.value}')
node.right = None
return root # root hasn't changed
while root:
root = del_leftmost_leaf(root)
Prints:
Removing 5
Removing 25
Removing 20
Removing 75
Removing 50
Removing 92
Removing 111
Removing 95
Removing 175
Removing 150
Removing 90
See demo
Second Algortihm
def del_leftmost_leaf(root):
if root.left is None and root.right is None:
print(f'Removing {root.value}')
return None # root has changed to None
parent = root
if root.left is None:
node = root.right
else:
node = root.left
while node.left:
parent = node
node = node.left
if node.right is None:
print(f'Removing {node.value}')
if parent.left is None:
parent.right = None
else:
parent.left = None
else:
node.right = del_leftmost_leaf(node.right)
return root # root hasn't changed
while root:
root = del_leftmost_leaf(root)
Prints:
Removing 5
Removing 25
Removing 20
Removing 66
Removing 80
Removing 75
Removing 50
Removing 92
Removing 111
Removing 95
Removing 166
Removing 200
Removing 175
Removing 150
Removing 90
See demo
If you only actually to remove the leftmost leaf node, a simple recursion can handle this problem pretty easily, but you'll need to use a return value from the function to communicate information back up the call stack. I suggest we return True if the current node is the leaf we're searching for, which should be deleted by its parent, and False otherwise:
def del_leaf(node):
if node is None:
raise ValueError("Can't remove a leaf node from an empty tree")
if node.left: # first recursive case
if del_leaf(node.left): # if the recursion returns True, our immediate child is a leaf
node.left = None # so delete it
return False
elif node.right: # second recursive case
if del_leaf(node.right):
node.right = None
return False
else: # base case, we're the leaf!
return True
Note that a function like this cannot ever delete the root value of a one-element tree, because it don't own the reference to that root node (that's probably in a variable in the calling scope). What it will do is return True to the caller in that case, so the calling code can delete the root reference itself, if necessary.
However, if you're really looking to remove the furthest leaf node from the root, with a preference for the leftmost if there are several leaves at the same depth, then you need a somewhat more sophisticated algorithm.
One way to do it that might be pretty efficient is to make sure each node keeps its height as an attribute. Then we can easily tell which branch of the tree we need to follow to find the leaf we want to remove.
# assume the nodes have a height attribute, leaf nodes have height 0
def update_height(node): # a helper function
node.height = 1 + max(node.left.height if node.left is not None else -1,
node.right.height if node.right is not None else -1)
# use this to initially set up heights (if you don't build them into the tree structure)
def setup_heights(node):
if node is None:
return
setup_heights(node.left)
setup_heights(node.right)
update_height(node)
def del_leaf(node):
if node is None:
raise ValueError("Can't remove from an empty tree")
if node.height == 0:
return True # the root needs to be removed by the caller
if self.height == 1: # we're the parent of a leaf, so delete one of our child nodes
if self.left is not None:
self.left = None
else:
self.right = None
elif self.left is not None and (self.right is None or
self.left.height >= self.right.height):
del_leaf(self.left)
else:
del_leaf(self.right)
update_height(node)
return False

Binary Search Tree Inorder Traversal Python giving recursion Error

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

Implementing Binary Search Tree (Python)

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.

Categories