How to Find the Minimum Value in the Binary Search Tree - python

How can I find the minimum node in this binary search tree. I can't make it work.
....................................................................
....................................................................
class BinarySearchTree:
def __init__(self, root):
self.root = root
self.left = None
self.right = None
def insert(self, node):
if node == self.root:
return
elif node < self.root:
if self.left:
self.left.insert(node)
else:
self.left = BinarySearchTree(node)
else:
if self.right:
self.right.insert(node)
else:
self.right = BinarySearchTree(node)
def search(self, target):
if target == self.root:
return True
else:
if target < self.root:
if self.left:
return self.left.search(target)
return False
if target > self.root:
if self.right:
return self.right.search(target)
return False
def find_min(self, root):
# traverse left subtree
while root is not None:
root = self.left
return root

def find_min(self):
# traverse left subtree
current = self
while self.left is not None:
current = self.left
return current.root
tree = BinarySearchTree("10")
tree.insert("20")
tree.insert("30")
print(tree.search("20")) # output: True
print(tree.search("40")) # output: False
print(tree.find_min()) # output: 10

Related

Delete a node from the binary tree with python

By making a node to be deleted from the tree, the node (case 1) can be a node with a single arm (right or left), or a node with both branches. In case the node to be deleted is an intermediate node with two branches, there are 2 different methods.
Method 1: the largest knot on the left arm or the smallest knot on the right arm, and
Method 2: The node in the branch with more depth (or the number of elements) is fulfilled so that the right or left arm is balanced.
Both methods have to be coded with separate functions.
How can I do these two methods?
class Node:
def __init__(self, data):
self.left = None
self.right = None
self.parent = None # new
self.data = data
def insert(self, data):
if self.data: # add by comparison
if data < self.data: # left if small
if self.left is None: # add left if left is blank
self.left = Node(data)
self.left.parent = self # new
else:
self.left.insert(data) # if left is not empty add to left sub-tree
elif data > self.data: # right if greater
if self.right is None: # add right if right is blank
self.right = Node(data)
self.right.parent = self # new
else: # if right is not empty add to sub-tree right
self.right.insert(data)
else:
self.data = data # the first dream of the tree
# print Tree
def PrintTree(self):
print( self.data,end='-')
if self.left:
self.left.PrintTree()
if self.right:
self.right.PrintTree()
def sizeTree(self):
if self.left and self.right:
return 1 + self.left.sizeTree() + self.right.sizeTree()
elif self.left:
return 1 + self.left.sizeTree()
elif self.right:
return 1 + self.right.sizeTree()
else:
return 1
def depth(self):
if self.left and self.right:
l = self.left.depth()
r = self.right.depth()
return 1 + max(l,r)
elif self.left:
return 1 + self.left.depth()
elif self.right:
return 1 + self.right.depth()
else:
return 1
# Use the insert method to add nodes
root = Node(25)
root.insert(12)
root.insert(10)
root.insert(22)
root.insert(5)
root.insert(36)
root.insert(30)
root.insert(40)
root.insert(28)
root.insert(38)
root.insert(48)
root.PrintTree()
"""
# 25,36,20,10,5,22,40,48,38,30,22,12,28
root = Node(25)
root.insert(36)
root.insert(20)
root.insert(10)
root.insert(5)
root.insert(22)
root.insert(40)
root.insert(48)
root.insert(38)
root.insert(30)
root.insert(12)
root.insert(28)
print("\n",root.sizeTree(),root.depth())
"""
Some time ago I was playing with this and came up with this code:
def search(self, value):
"""
Recursively looks to the left and right of Tree depending on the provided value
and returns it if it is present within Tree.
Args:
value (int): value to be searched for within Tree
Returns:
value if value exists in Tree otherwise None
"""
if value < self.data:
if self.left is None:
return None
return self.left.search(value)
elif value > self.data:
if self.right is None:
return None
return self.right.search(value)
else:
return self.data
def _findNodeToDelete(self, value, previous=None):
"""
Recursively looks to the left and right of Tree depending on the provided value
and returns it if it is present within Tree.
Args:
value (int): value to be searched for within Tree
Returns:
value if value exists in Tree otherwise None
"""
if value < self.data:
if self.left is None:
return None
return self.left._findNodeToDelete(value, self)
elif value > self.data:
if self.right is None:
return None
return self.right._findNodeToDelete(value, self)
else:
return self, previous
def _mergeNodes(self, target):
self.data = target.data
self.left = target.left
self.right = target.right
def deleteNode(self, value, start=None):
if self.search(value):
to_delete, parent = self._findNodeToDelete(value, start)
if to_delete.right and to_delete.left:
new_value = to_delete.right.min
to_delete.data = new_value
to_delete.right.deleteNode(new_value, to_delete)
elif to_delete.left:
to_delete._mergeNodes(to_delete.left)
elif to_delete.right:
to_delete._mergeNodes(to_delete.right)
else:
if parent:
if parent.data > value:
parent.left = None
else:
parent.right = None
else:
self.data = None
Note, I don't use parent attribute, rather calculate it while deleting.

Delete a segment from BST in Python

first post here. I am supposed to build a BST (which I have done) and create a deleteNode function. I keep trying to run the function but it is unfortunately not working.
#deleteFunction#
def deleteNode(self, data):
if self is None: ##none is left and right val
return self
if data < self.data: #if input is less than current
self.left = self.deleteNode(self.left, data) #go to the left node
elif (data > self.data): #if input is higher, go to right node
self.right = self.deleteNode(self.right, data)
else:
if self.left is None:
temp = self.right #if left is none then assign temp to right
self.left = None
return temp
elif self.right is None: #if right is none, assign temp to left
temp = self.left
self.left = None
return temp
temp = findMinNode(self.right) ##node with two children, get the smallest right subtree
self.data = temp.data ##copy the right small subtree
self.right = deleteNode(self.right, temp.data) #delete smallest right subtree
return self
##Execution code:##
print("Maximum node in BT: \n", dTree.findMaxNode())
print("Minimum node in BT: \n",dTree.findMinNode())
print("Post Order: \n", dTree.postOrderTrav())
print("Pre Order: \n", dTree.preOrderTrav())
print("In Order: \n", dTree.inOrderTrav())
dTree.deleteNode(4)
print("deletion of one node: ")
print (dTree.inOrderTrav())
I keep receiving the following error:
line 262, in <module> dTree.deleteNode(4)
File "C:/Users", line 215, in deleteNode self.right = self.deleteNode(self.right, data)
TypeError: deleteNode() takes 2 positional arguments but 3 were given
200
This is my favorite version of deleting a node in BST - use deleteNode function, with root being the root node and key being the node value that you want to delete.
class DeletingNodeBST:
def successor(self, root):
root = root.right
while root.left:
root = root.left
return root.val
def predecessor(self, root):
root = root.left
while root.right:
root = root.right
return root.val
def deleteNode(self, root, key):
if not root:
return None
if key > root.val:
root.right = self.deleteNode(root.right, key)
elif key < root.val:
root.left = self.deleteNode(root.left, key)
else:
if not (root.left or root.right):
root = None
elif root.right:
root.val = self.successor(root)
root.right = self.deleteNode(root.right, root.val)
else:
root.val = self.predecessor(root)
root.left = self.deleteNode(root.left, root.val)
return root
Note that root is the root node, which can be created with:
class Node:
def __init__(self, key):
self.key = key
self.left = None
self.right = None

Function to create a binary search tree recursively

Picture of Question with specific details
I'm trying to write a function that creates a binary search tree. Here's what I have so far:
def add_items(bst, low, high):
if low == high:
bst.insert(high)
return
else:
left = add_items(bst, low, high)
right = add_items(bst, low, high)
item = BinarySearchTreeMap.Item(low)
node = BinarySearchTreeMap.BinarySearchTreeMap.Node(item)
node.left = left
node.right = right
return node
The problems I noticed with this is that the function returns a node when it finishes all the recursive calls. I want to return the root of this binary search tree, but I'm not sure how to return it at the end. The picture includes a more detailed description of what I am trying to do. I appreciate any help, advice, or ideas anyone may have. add_items is actually sort of a helper function as it is called by this little snippet of code:
def create_complete_bst(n):
bst = BinarySearchTreeMap.BinarySearchTreeMap()
add_items(bst, 1, n)
return bst
P.S. here is the binary search tree class that I have been provided with and am using in this program
class BinarySearchTreeMap:
class Item:
def __init__(self, key, value=None):
self.key = key
self.value = value
class Node:
def __init__(self, item):
self.item = item
self.parent = None
self.left = None
self.right = None
def num_children(self):
count = 0
if (self.left is not None):
count += 1
if (self.right is not None):
count += 1
return count
def disconnect(self):
self.item = None
self.parent = None
self.left = None
self.right = None
def __init__(self):
self.root = None
self.size = 0
def __len__(self):
return self.size
def is_empty(self):
return len(self) == 0
# raises exception if not found
def __getitem__(self, key):
node = self.find(key)
if (node is None):
raise KeyError(str(key) + " not found")
else:
return node.item.value
# returns None if not found
def find(self, key):
curr = self.root
while (curr is not None):
if (curr.item.key == key):
return curr
elif (curr.item.key > key):
curr = curr.left
else: # (curr.item.key < key)
curr = curr.right
return None
# updates value if key already exists
def __setitem__(self, key, value):
node = self.find(key)
if (node is None):
self.insert(key, value)
else:
node.item.value = value
# assumes key not in tree
def insert(self, key, value=None):
item = BinarySearchTreeMap.Item(key, value)
new_node = BinarySearchTreeMap.Node(item)
if (self.is_empty()):
self.root = new_node
self.size = 1
else:
parent = self.root
if(key < self.root.item.key):
curr = self.root.left
else:
curr = self.root.right
while (curr is not None):
parent = curr
if (key < curr.item.key):
curr = curr.left
else:
curr = curr.right
if (key < parent.item.key):
parent.left = new_node
else:
parent.right = new_node
new_node.parent = parent
self.size += 1
# raises exception if key not in tree
def __delitem__(self, key):
node = self.find(key)
if (node is None):
raise KeyError(str(key) + " is not found")
else:
self.delete_node(node)
# assumes key is in tree + returns value assosiated
def delete_node(self, node_to_delete):
item = node_to_delete.item
num_children = node_to_delete.num_children()
if (node_to_delete is self.root):
if (num_children == 0):
self.root = None
node_to_delete.disconnect()
self.size -= 1
elif (num_children == 1):
if (self.root.left is not None):
self.root = self.root.left
else:
self.root = self.root.right
self.root.parent = None
node_to_delete.disconnect()
self.size -= 1
else: #num_children == 2
max_of_left = self.subtree_max(node_to_delete.left)
node_to_delete.item = max_of_left.item
self.delete_node(max_of_left)
else:
if (num_children == 0):
parent = node_to_delete.parent
if (node_to_delete is parent.left):
parent.left = None
else:
parent.right = None
node_to_delete.disconnect()
self.size -= 1
elif (num_children == 1):
parent = node_to_delete.parent
if(node_to_delete.left is not None):
child = node_to_delete.left
else:
child = node_to_delete.right
child.parent = parent
if (node_to_delete is parent.left):
parent.left = child
else:
parent.right = child
node_to_delete.disconnect()
self.size -= 1
else: #num_children == 2
max_of_left = self.subtree_max(node_to_delete.left)
node_to_delete.item = max_of_left.item
self.delete_node(max_of_left)
return item
# assumes non empty subtree
def subtree_max(self, curr_root):
node = curr_root
while (node.right is not None):
node = node.right
return node
def inorder(self):
for node in self.subtree_inorder(self.root):
yield node
def subtree_inorder(self, curr_root):
if(curr_root is None):
pass
else:
yield from self.subtree_inorder(curr_root.left)
yield curr_root
yield from self.subtree_inorder(curr_root.right)
def __iter__(self):
for node in self.inorder():
yield node.item.key
After revising with suggestions:
def create_complete_bst(n):
bst = BinarySearchTreeMap.BinarySearchTreeMap()
add_items(bst, 1, n)
return bst
def add_items(bst, low, high):
if low == high:
bst.insert(high)
return
elif high < low:
return
else:
mid = (low+high) // 2
bst.insert(mid)
add_items(bst, low, mid-1)
add_items(bst, mid+1, high)
return bst

How can I find visited nodes called in functions?

Here's my programme of Binary Search Tree, all the functions are working in uploading system, except the last one, I somehow have to find out which of the Nodes I visited throughout calling previous functions. Any ideas?
class Node:
def __init__(self, value):
self.left = None
self.right = None
self.data = value
class BinarySearchTree:
def __init__(self):
self.root = None
def insert(self, value):
if self.root is None:
self.root = Node(value)
else:
self._insert(value, self.root)
def _insert(self, value, curNode):
if value < curNode.data:
if curNode.left is None:
curNode.left = Node(value)
else:
self._insert(value, curNode.left)
else:
if curNode.right is None:
curNode.right = Node(value)
else:
self._insert(value, curNode.right)
def fromArray(self, array):
for i in range(len(array)-1):
value = array[i]
self.insert(value)
i += 1
def search(self, value):
if self.root is not None:
return self._search(value, self.root)
else:
return False
def _search(self, value, curNode):
if value == curNode.data:
return True
elif value < curNode.data and curNode.left is not None:
self._search(value, curNode.left)
elif value > curNode.data and curNode.right is not None:
self._search(value, curNode.right)
else:
return False
def min(self):
curNode = self.root
while curNode.left is not None:
curNode = curNode.left
return curNode
def max(self):
curNode = self.root
while curNode.right is not None:
curNode = curNode.right
return curNode
def visitedNodes(self):
pass
And it has to return the values of nodes in list.
The straight forward answer would be to add a visited flag to each node, that is explicitly flipped in each of your functions when a Node is visited:
class Node:
def __init__(self, value):
self.left = None
self.right = None
self.data = value
self.visited = False
and then:
def _search(self, value, curNode):
curNode.visited = True
if value == curNode.data:
return True
# etc., unchanged
Same for min and max, and finally:
def visitedNodes(self, current=self.root, accumulator=[]):
if current == None:
return
if current == self.root:
accumulator = []
if current.visited:
accumulator.append(current)
visitedNodes(current.left)
visitedNodes(current.right)
return accumulator
This is just one implementation, there are many other ways to do this. I also assume this function, which traverses the whole tree, should not set the visited flag.
If you don't want to modify your current code, maybe this can help you:
class Node:
def __init__(self, value):
self.left = None
self.right = None
self._data = value
self.visited = False
#property
def data(self):
self.visited = True
return self._data
#data.setter
def data(self, value):
self.visited = False
self._data = value
n = Node(3)
print(n.visited)
print(n.data)
print(n.visited)
Output:
False
3
True
Then in your visitedNodes method you would have to look at the visited attribute of everynode. (Which will be slow)
Other way of doing it is adding a new set attribute to your BinarySearchTree and manually add a node each time you look at it, this will make you modify your code.

How to count the leaves of a Binary Tree?

class Node:
def __init__(self, item, left = None, right = None):
self.item = item
self.left = left
self.right = right
class BST:
def __init__(self):
self.root = None
def recurse_add(self, ptr, item):
if ptr == None:
return Node(item)
elif item < ptr.item:
ptr.left = self.recurse_add(ptr.left, item)
elif item > ptr.item:
ptr.right = self.recurse_add(ptr.right, item)
return ptr
Here is my attempt:
def count_leaves(self):
ptr = self.root
counter = 0
if ptr.left is None and ptr.right is None:
counter += 1
if ptr.left:
counter += self.count_leaves()
if ptr.right:
counter += self.count_leaves()
return counter
I got a RecursionError, is there anyway that I could fix this?Can anyone explain to me how I would count the leaves of the binary tree?
You are always repeating from the self node when you are counting leaves.
def count_leaves(self):
ptr = self.root # reseting at the root
...
counter += self.count_leaves() # recurses from the top of the tree
Your secondary problem seems to be related to how you are adding nodes.
For example,
def recurse_add(self, ptr, item):
if prt == None:
# say this is false
ptr.left = self.recurse_add(ptr.left, item)
...
return ptr # The recursive call will return 'ptr.left'
So, basically ptr.left = ptr.left in the case that ptr != None
You need to iterate down. I generally implement all recursive methods onto the Node class rather than pass along a pointer in the Tree class.
class Node(object):
def __init__(self, item, left = None, right = None):
self.item = item
self.left = left
self.right = right
def is_leaf(self):
return self.right is None and self.left is None
def add(self, item):
if item <= self.item:
self.left = Node(item) if self.left is None else self.left.add(item)
elif item > self.item:
self.right = Node(item) if self.right is None else self.right.add(item)
return self
def count_leaves(self):
counter = 0
if self.is_leaf():
counter += 1
if self.left is not None:
counter += self.left.count_leaves()
if self.right is not None:
counter += self.right.count_leaves()
return counter
Now, just delegate the methods to the root from the tree, if you have a root.
class BST:
def __init__(self):
self.root = None
def is_empty(self):
return self.root is None
def add(self, item):
if self.is_empty():
self.root = Node(item)
else:
self.root.add(item)
def count_leaves(self):
return 0 if self.is_empty() else self.root.count_leaves()

Categories

Resources