Skip to content
Permalink
main
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
""" Basic BST code for inserting (i.e. building) and printing a tree
Your ***second standard viva task*** (of 5) will be to implement a find method into
the class BinaryTree from pseudocode. See the lab task sheet for Week 5.
Your ***first advanced viva task*** (of 3) will be to implement a remove (delete) method
into the class Binary Tree from partial pseudocode. See the lab task sheet for Week 5 (available in Week 5).
There will be some ***introductory challenges*** in Week 4, with solutions released in Week 5.
It is STRONGLY RECOMMENDED you attempt these!
Since the given code is in python it is strongly suggested you stay with python; but
if you want to reimplement as C++ this is also OK (see the Week 5 lab sheet guidance).
"""
import math
""" Node class
"""
class Node:
def __init__(self, data = None):
self.data = data
self.left = None
self.right = None
""" BST class with insert and display methods. display pretty prints the tree
"""
class BinaryTree:
def __init__(self):
self.root = None
def insert(self, data):
if self.root is None:
self.root = Node(data)
else:
self._insert(data, self.root)
def _insert(self, data, cur_node):
if data < cur_node.data:
if cur_node.left is None:
cur_node.left = Node(data)
else:
self._insert(data, cur_node.left)
elif data > cur_node.data:
if cur_node.right is None:
cur_node.right = Node(data)
else:
self._insert(data, cur_node.right)
else:
print("Value already present in tree")
def display(self, cur_node):
lines, _, _, _ = self._display(cur_node)
for line in lines:
print(line)
def _display(self, cur_node):
if cur_node.right is None and cur_node.left is None:
line = '%s' % cur_node.data
width = len(line)
height = 1
middle = width // 2
return [line], width, height, middle
if cur_node.right is None:
lines, n, p, x = self._display(cur_node.left)
s = '%s' % cur_node.data
u = len(s)
first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s
second_line = x * ' ' + '/' + (n - x - 1 + u) * ' '
shifted_lines = [line + u * ' ' for line in lines]
return [first_line, second_line] + shifted_lines, n + u, p + 2, n + u // 2
if cur_node.left is None:
lines, n, p, x = self._display(cur_node.right)
s = '%s' % cur_node.data
u = len(s)
first_line = s + x * '_' + (n - x) * ' '
second_line = (u + x) * ' ' + '\\' + (n - x - 1) * ' '
shifted_lines = [u * ' ' + line for line in lines]
return [first_line, second_line] + shifted_lines, n + u, p + 2, u // 2
left, n, p, x = self._display(cur_node.left)
right, m, q, y = self._display(cur_node.right)
s = '%s' % cur_node.data
u = len(s)
first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + y * '_' + (m - y) * ' '
second_line = x * ' ' + '/' + (n - x - 1 + u + y) * ' ' + '\\' + (m - y - 1) * ' '
if p < q:
left += [n * ' '] * (q - p)
elif q < p:
right += [m * ' '] * (p - q)
zipped_lines = zip(left, right)
lines = [first_line, second_line] + [a + u * ' ' + b for a, b in zipped_lines]
return lines, n + m + u, max(p, q) + 2, n + u // 2
def find_i(self, target):
'''Iterative method to search a given target in BST.'''
if self.root: # if there is a root node
cur_node = self.root # set the root of BST as cur_node
while cur_node is not None: # while there is a node
if cur_node.data == target: # if the cur_node is equal to the target
return True # return True
elif cur_node.data > target: # if the cur_node is bigger than the target
cur_node = cur_node.left # set the cur_node to the node on the left side
else: # if the cur_node is smaller than the target
cur_node = cur_node.right # set the cur_node to the node on the right side
return False # if the target is not found return False
else: # if there isn't a root node
return None # return None
def find_r(self, target):
'''Recursive method to search a given target in BST.'''
if self.root: # if there is a root node
if self._find_r(target, self.root): # if the sub-method _find_r finds the target
return True # return True
return False # if the target is not found return False
else: # if there isn't a root node
return None # return None
def _find_r(self, target, cur_node):
'''Sub-method for find_r method to search a given target in BST.'''
if target > cur_node.data and cur_node.right: # if the target is bigger than cur_node
# and there is a node to the right
return self._find_r(target, cur_node.right) # return the _find_r function with the right node as argument
elif target < cur_node.data and cur_node.left: # if the target is smaller than the cur_node
# and there is a node to the left
return self._find_r(target, cur_node.left) # return the _find_r function with the left node as argument
if target == cur_node.data: # if the target is equal to the current node
return True # return True
def remove(self, target):
'''Method that removes a node and reorganises the BST.'''
if self.root is None: # if there isn't a root node
return False # return False
#if tree root is the target
elif self.root.data == target: # if the root node is equal to target
if self.root.left is None and self.root.right is None: # if there are no other nodes than root node then
self.root = None # the root node is None
elif self.root.left and self.root.right is None: # if there is only node to the left of the root node
self.root = self.root.left # set the left node as root node
elif self.root.left is None and self.root.right: # if there is only node to the right of the root node
self.root = self.root.right # set the right node as root node
elif self.root.left and self.root.right: # if there is a right node and left node
self.if_left_and_right(self.root) # call if_left_and_right function
#if tree root is not the target
parent = None # set parent node to None
node = self.root # set node to root node
while node and node.data != target: # while there is a node and the node is not equal to the target
parent = node # set node as parent
if target < node.data: # if the target is smaller than the node
node = node.left # set the left node of the current node as current node
elif target > node.data: # if the target is bigger than the node
node = node.right # set the right node of the current node as current node
#target not found
if node is None or node.data != target: # if there isn't any node or the node is not equal to target
return False # return False
#target has no children
elif node.left is None and node.right is None: # if there isn't left or right node from the current node
if target < parent.data: # if the target is smaller than the parent
parent.left = None # set the left parent to None
else:
parent.right = None # set the right parent to None
return True # return True
#target has only left child
elif node.left and node.right is None: # if there is only left node from the current node
if target < parent.data: # if the target is smaller than the parent
parent.left = node.left # set the left parent to left node
else:
parent.right = node.left # set the right parent to left node
return True # return True
#target has only right child
elif node.right and node.left is None: # if there is only left node from the current node
if target < parent.data: # if the target is smaller than the parent
parent.left = node.right # set the left parent to right node
else:
parent.right = node.right # set the right parent to right node
return True # return True
#target has left and right child
else: # if there is node to the left and to the right
self.if_left_and_right(node) # call if_left_and_right function
def if_left_and_right(self, node):
'''Sub-method for deletion method.
Reorganise the BST when the delete node has left and right children.'''
delNodeParent = node # set the target node as delNodeParent
delNode = node.right # set right node of the target as delNode
while delNode.left: # while there is node to the left of the delNode
delNodeParent = delNode # set delNodeParent as delNode
delNode = delNode.left # set delNode as left node
node.data = delNode.data
if delNode.right: # if there is a node to the right of delNode
if delNodeParent > delNode.data: # if delNodeParent is bigger than the delNode
delNodeParent.left = delNode.right
else:
delNodeParent.right = delNode.right
else:
if delNode.data < delNodeParent.data:
delNodeParent.left = None
else:
delNodeParent.right = None
#example calls, which construct and display the tree
bst = BinaryTree()
bst.insert(4)
bst.insert(2)
bst.insert(6)
bst.insert(1)
bst.insert(3)
bst.insert(5)
bst.insert(7)
bst.insert(8)
#bst.insert(9)
#bst.insert(10)
#bst.insert(11)
##bst.insert(12)
##bst.insert(13)
##bst.insert(14)
##bst.insert(15)
##bst.insert(100)
##bst.insert(200)
bst.display(bst.root)
print(bst.find_i(4))
print(bst.find_i(8))
print(bst.find_r(3))
print(bst.find_r(10))
print(bst.remove(4))
bst.display(bst.root)
print(bst.find_r(3))
print(bst.find_i(8))