I'm trying to implement insert function of bst but my recursive approach only inserts the first value. My approach was to traverse until the empty child and set that node to new value.
class BSTNode(object):
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def insert(self, val):
if self.root is None:
self.root = BSTNode(val)
else:
self.insertNode(self.root,val)
def insertNode(self,node, val):
if node is None:
node = BSTNode(val)
return
elif val <= node.val:
node.left = self.insertNode(node.left, val)
elif val > node.val:
node.right = self.insertNode(node.right, val)
bst = new BST()
bst.insert(5)
bst.insert(10)
You're not returning BSTNode in insertNode (so you create a node but return None). You should do this instead:
if node is None:
return BSTNode(val)
So the full method becomes:
def insertNode(self, node, val):
if node is None:
return BSTNode(val)
elif val <= node.val:
node.left = self.insertNode(node.left, val)
elif val > node.val:
node.right = self.insertNode(node.right, val)
return node
It might be helpful to first create a node class... it's easier to think of a node alone than it is to think about a Tree.
class Node:
def __init__(self,value):
self.value = value
self.left = None
self.right = None
def insert_value(self,value):
# there are 3 cases
if not self.value: # in one case this node has no value
self.value = value
elif value < self.value: # if value is less than this nodes value
# then insert it to the left
if not self.left:
self.left = Node(value)
else:
self.left.insert_value(value)
else: # otherwise if value is greater than or equal to this nodes value
# then insert it to the right
if not self.right:
self.right = Node(value)
else:
self.right.insert_value(value)
Once you have this Node class the tree implementation becomes trivial.
class BST:
def __init__(self,root_value=None):
self.root = Node(root_value)
def insert_value(self,value):
self.root.insert_value(value)
bst = BST()
bst.insert_value(5)
bst.insert_value(10)
print(bst.root)
Now you certainly do not have to solve this in this fashion ... but it makes it easier to reason about (at least for me).
Related
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.
The logic I tried:
def min_tree_value(self):
while self.left:
self.left = self.left.left
return self.data
Actual Python program Logic:
def min_tree_value(self):
if self.left is None:
return self.data
return self.left.min_tree_value()
The actual Python program logic is in recursion form. I tried the same logic in While loop()
I'm not sure whether my logic is correct. Do help me to figure out the incorrect logic and point where I'm Wrong.
Your logic is almost there, but not quite:
def min_tree_value(self):
node = self
while node.left:
# don't change the structure by rebinding node.left,
# but iterate the tree by moving along nodes!
node = node.left
return node.data
Note that in the original code, you never reassign self before returning its value, so you always returned the root value.
First of all, the question asks about finding the minimum element in a binary tree.
The algorithm you used, will find the minimum element in the Binary Search Tree (as the leftmost element is the minimum).
For finding minimum element in a simple Binary Tree, use the following algorithm:
# Returns the min value in a binary tree
def find_min_in_BT(root):
if root is None:
return float('inf')
res = root.data
lres = find_min_in_BT(root.leftChild)
rres = find_min_in_BT(root.rightChild)
if lres < res:
res = lres
if rres < res:
res = rres
return res
Additions to the answer after OP changed the question:
The logic for the algorithm you tried is correct, with a small correction in the implementation: self = self.data. Both of them find the leftmost element.
I have also tested both the functions which return the same output:
class Node:
def __init__(self, data):
self.left = None
self.right = None
self.data = data
def insert(self, data):
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
def findval(self, lkpval):
if lkpval < self.data:
if self.left is None:
return str(lkpval)+" Not Found"
return self.left.findval(lkpval)
elif lkpval > self.data:
if self.right is None:
return str(lkpval)+" Not Found"
return self.right.findval(lkpval)
else:
print(str(self.data) + ' is found')
def PrintTree(self):
if self.left:
self.left.PrintTree()
print( self.data),
if self.right:
self.right.PrintTree()
def min_tree_value_original(self):
if self.left is None:
return self.data
return self.left.min_tree_value_original()
def min_tree_value_custom(self):
while self.left:
self = self.left
return self.data
root = Node(12)
root.insert(6)
root.insert(14)
root.insert(3)
root.insert(3)
root.insert(1)
root.insert(0)
root.insert(-1)
root.insert(-2)
print(root.min_tree_value_original())
print(root.min_tree_value_custom())
Output:
-2
-2
Here -2 is the smallest and the leftmost element in the BST.
Being a beginner, I have been trying to implement Binary Tree in python. And have been available to implement a lot successfully with only one problem that I am unable to return a list of all the elements (traverse())in the binary tree. I am using two classes here, Node and BinaryTree.
Node Class
class Node:
def __init__(self, val):
self.value = val
self.left = None
self.right = None
Traverse method to return all the elements in the binary tree.
def traverse(self): #<-- Problem here
tree_elements = []
if self.left != None:
self.left.traverse()
tree_elements.append(self.value)
#debug
print(self.value, end=" ")
if self.right != None:
self.right.traverse()
return tree_elements
def addNode(self, node):
if node.value < self.value and node.value != self.value:
if self.left == None:
self.left = node
else:
self.left.addNode(node)
elif node.value > self.value and node.value != self.value:
if self.right == None:
self.right = node
else:
self.right.addNode(node)
def search(self, val):
if val == self.value:
return "Found"
elif val < self.value:
if self.left != None:
return self.left.search(val)
else:
return "Not Found "
elif val > self.value:
if self.right != None:
return self.right.search(val)
else:
return "Not Found"
Binary Tree
class BinaryTree:
def __init__(self):
self.root = None
def addVlaue(self, val):
node = Node(val)
if self.root == None:
self.root = node
else:
self.root.addNode(node)
def search(self, val):
if self.root == None:
return False
else:
return self.root.search(val)
def traverse(self):
if self.root == None:
return "no data"
else:
return self.root.traverse()
Problem:
traverse method has to return all the elements in the binary tree, but i have been getting only first value of the tree.
example:
elements: 100 18 46 5 65 5 31 71 94 43 #input in the tree
output from tree:
5 18 31 43 46 65 71 94 100 #expected output
[100] #output from the tree
The tree_elements list needs to go along the recurvise calls, collecting each node along the way. In other words, it must be passed as an argument to traverse calls (except when calling traverse for the root node).
Otherwise a new list is created and discarded in each traverse call (since you never do anything with the return value of traverse during its recursion), except for the top recursive call which returns the root element only.
Try this implementation:
def traverse(self, tree_elements=None):
if tree_elements is None:
tree_elements = []
if self.left != None:
self.left.traverse(tree_elements=tree_elements)
tree_elements.append(self.value)
if self.right != None:
self.right.traverse(tree_elements=tree_elements)
return tree_elements
So this is my code below, my thought process is that if the smallest value in the tree is less than the root and the largest value in the tree is greater than the root it should check if the BST is valid
def min(self):
while self.left:
self.root = self.left
return self.root
def max(self):
while self.right:
self.root = self.right
return self.value
def valid(self):
min = min(self.left)
max = max(self.right)
if self.root > min and self.root < max:
return True
Don't reuse the names min and max. They already refer to built-in functions.
Your min and max functions change the tree, by changing self.root.
You should be validating that the values of the left and right child nodes are correct relative to the parent node, then validating that each of the BSTs rooted at those child nodes is itself valid.
class Node:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
def valid(self):
if self.left and self.left.value > self.value:
return False
if self.right and self.right.value < self.value:
return False
return all(node.valid() for node in (self.left, self.right) if node)
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.