adding an element to binary search tree - python

Hi my question is how can i fix the code for my add function for my binary search tree program.
class BTNode2:
def __init__(self,d,l,r):
self.data = d
self.left = l
self.right = r
self.mult = 1
And this is the add method
def add(self, d):
if (self < d.data):
if (d.left != None):
add(self, d.left)
else:
d.left = BTNode2(self)
else:
if (d.right != None):
add(self, d.right)
else:
d.right = BTNode2(self)
return
This is the error i get when i try to run the add method:
AttributeError: 'str' object has no attribute 'data'

In essence, you swapped the parameters of the add function, since self is the tree here, and d the data element to add. Furthermore in order to construct such BTNode2s with only one parameter, you should add a default value for l and r. Finally depending on what mult does, you might want to change this in the add algorithm, but it is not really clear what it represents.
So we can fix this to:
class BTNode2:
def __init__(self, d, l=None, r=None):
self.data = d
self.left = l
self.right = r
self.mult = 1
def add(self, d):
if d < self.data:
if self.left is not None:
self.left.add(d)
else:
self.left = BTNode2(d)
else:
if self.right is not None:
self.right.add(d)
else:
self.right = BTNode2(d)

Related

find a path to a given node in binary tree - Python

I'm stuck finding the path of the given node so I can find the right side but not the left side.
class Node:
def __init__(self, key):
self.left = None
self.right = None
self.val = key
def path(self, k):
if not self.val:
return []
if self.val == k:
return [self.val]
res = self.left.path(k)
if res:
return [self.val] + res
res = self.right.path(k)
if res:
return [self.val] + res
return []
For example, when I search for 5 in X="+ * + 5 7 4 1 6", the output is like ['+', '*', '+', '5'] but when I try to search for any number on the lift subtree, it gives me this error:
[Previous line repeated 1 more time]
AttributeError: 'NoneType' object has no attribute 'path'
Before accessing a method like path you should ensure that the object really is a Node instance, and not None.
Not the problem, but not self.val will also be a true expression when that val is 0, which seems like a valid key for a node... I suppose this test is there to detect a node with a None value. Usually such code is used when a tree is always created with at least one node instance, even when it is empty. This is not good practice. An empty tree should not have nodes at all, not even one with a None value.
So correct to:
class Node:
def __init__(self, key):
self.left = None
self.right = None
self.val = key
def path(self, k):
if self.val == k:
return [self.val]
if self.left:
res = self.left.path(k)
if res:
return [self.val] + res
if self.right:
res = self.right.path(k)
if res:
return [self.val] + res
return []

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.

Binary Search Tree Find minimum not clear

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.

Creating a binary tree

I'm trying to create a tree from a flat list. I need to define a function called tree_from_flat_list. For any node at index position i, the left child is stored at index position 2*i, and the right child is stored at index position 2*i+1. :
class BinaryTree:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def get_left(self):
return self.left
def get_right(self):
return self.right
def set_left(self, tree):
self.left = tree
def set_right(self, tree):
self.right = tree
def set_data(self, data):
self.data = data
def get_data(self):
return self.data
def create_string(self, spaces):
info = ' ' * spaces + str(self.data)
if self.left != None:
info += '\n(l)' + self.left.create_string(spaces+4)
if not self.right == None:
info += '\n(r)' + self.right.create_string(spaces+4)
return info
def __str__(self):
representation = self.create_string(0)
return representation
def tree_from_flat_list(node_list):
if node_list != None:
root_index = 1
list1 = []
list2 = []
root = node_list[root_index]
left_sub_tree = list1.append(node_list[2*root_index])
right_sub_tree = list2.append(node_list[2*root_index+1])
tree = BinaryTree(root)
tree.set_left(tree_from_flat_list(left_sub_tree))
tree.set_right(tree_from_flat_list(right_sub_tree))
return tree
When I try running this:
def test():
flat_list = [None, 10, 5, 15, None, None, 11, 22]
my_tree = tree_from_flat_list(flat_list)
print(my_tree)
test()
I should get the output:
10
(l) 5
(r) 15
(l) 11
(r) 22
Edit: Still stuck on what I should be doing for the function. Any help is still appreciated.
the amount of spaces inbetween is the height of the tree and the l and r represent if they are a left child or a right child. This would looks like:
10
/ \
5 15
/ \
11 22
but instead I only get:
10
How should I edit my tree_from_flat_list function so that this works. Any help is appreciated. Thank you.
The essence of your problem is in these lines:
left_sub_tree = list1.append(node_list[2*root_index])
right_sub_tree = list2.append(node_list[2*root_index+1])
The append function sets doesn't return anything - it appends to the list. This sets your left and right sub trees to None.
The list format seems to be a variant of a binary heap where elements can be None. I think you can simplify this quite a bit:
class BinaryTree(object):
def __init__(self, label, left, right):
self.label = label
self.left = left
self.right = right
def tree_from_flat_list(ls, index=1):
if index < len(ls) and ls[index] is not None:
left = tree_from_flat_list(ls, 2*index)
right = tree_from_flat_list(ls, 2*index+1)
return BinaryTree(ls[index], left, right)
I wonder though why you don't store the left and right children in indices 2*i+1 and 2*i+2, like in a binary heap; then you don't need to have the None at the beginning.

python how to implement a list into a tree?

I have a list of data indicates what direction is going next like:
[[0,1,0,0,1],[0,0,1],[0,0],[0,1,1,1,0]]
I want to implement this data into a tree structure like:
The number inside the node is how many people walked on this direction.
I have a Tree class that I write myself like this:
class Tree(object):
def __init__(self):
self.left = None
self.right = None
self.data = 0
def insert(self,num):
self.data = self.data + 1
if num == 0:
if self.left == None:
self.left = Tree()
return self.left
elif num == 1:
if self.right == None:
self.right = Tree()
return self.right
How can I do this? I tried to make it in a recursive way but turns out it's not saving under root but build_tree which is a variable that I tried to make as the recursive pointer.
root = Tree()
for route in data:
build_tree = root
for i in range (0,len(route)):
num = route[i]
build_tree = build_tree.insert(num)
Thanks!
Edit: This code actually works just like Blender said in comment. I think I had something wrong when I implemented it to a more complex code.
Also thanks John La Rooy for the suggestion and Kevin K. for the example!
Try making a separate class for the node like so
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
Then in your Tree class initialize self.root and declare your functions with recursion within Tree
Edit: Here is an example.

Categories

Resources