Binary Tree Conditional Insert - python

I am trying to write a logic to insert a node into a binary tree.
The node looks like this
class BinTree:
def __init__(self, Id):
self.Id = Id
self.NodeCounter = 1
self.left = None
self.right = None
I need to insert a new node only if it doesnt exist in the tree but increment the counter if it exists already.
As of now, what im doing is whenever i get a new element to insert, i first search it in the binary tree, if the node is found i increment the NodeCounter by 1, otherwise I again start traversing from root node and then go and insert the new node
The problem here is that for every new node, i am traversing the tree twice which i dont want… And when i am trying to search and insert at the same time,the counters get messed because of recursion.
Is there a way I can achieve this?
Any tips would be appreciated

i first search it in the binary tree
...this would only be an efficient process if your binary tree is a binary search tree (BST). I'll assume that is what we are talking about.
if the node is found i increment the NodeCounter by 1, otherwise I again start traversing from root node and then go and insert the new node
Why would you start from the root again? When you did the search and didn't find the node, there was a last node that you visited. Just attach the new node to it.
Here is a possible implementation:
class Node:
def __init__(self, id):
self.id = id
self.nodeCounter = 1
self.left = None
self.right = None
class BinTree:
def __init__(self):
self.root = None
def add(self, id):
self.root = self.addrecur(self.root, id)
def addrecur(self, node, id):
if not node:
node = Node(id)
elif id == node.id:
node.nodeCounter += 1
elif id < node.id:
node.left = self.addrecur(node.left, id)
else:
node.right = self.addrecur(node.right, id)
return node
def __repr__(self):
return self.indented(self.root)
def indented(self, node, indent=""):
if not node:
return ""
return (self.indented(node.right, indent + " ")
+ f"{indent}{node.id} ({node.nodeCounter})\n"
+ self.indented(node.left, indent + " "))
tree = BinTree()
tree.add(4)
tree.add(2)
tree.add(3)
tree.add(2)
tree.add(6)
tree.add(5)
tree.add(5)
print(tree)
This outputs the tree in side-ways view (root at left) with the node count in parentheses:
6 (1)
5 (2)
4 (1)
3 (1)
2 (2)

Related

How can we Display and store a binary search tree in Django

I have written the program for Binary Search Tree but does not know how can i save it in the Django Database. How can i store it in the models:
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)
User can add and delete a tree and On adding a tree, user should be prompted to enter at least 3 nodes...
A binary search tree structure should be displayed when a tree is selected, with its
respective nodes in the order of insertion.....
How can all the changes that have been done by the user can be reflected back into the database..

Recursive insert into a tree with 4 children

I'm trying to construct a tree in Python that can take 4 children. The children are defined as an array.
What I'm struggling with is inserting recursively into this tree.
Here is what I've done so far:
Node Class:
class node:
def __init__(self,value,city,children=[None,None,None,None]):
self.value = value
self.children = children
self.city = city
Tree Class:
from node import *
from isFull import *
class tree:
root = None
def __int__(self):
self.root = None
def insert(self, city, value):
if self.root == None:
self.root = node(value, city, children=[None,None,None,None])
else:
self.rec_insert(city, value, self.root, 0)
def rec_insert(self, city, value, nodes, index):
if nodes.children[index] is None:
nodes.children[index] = node(value, city, children=[None,None,None,None])
return
elif index < 3:
self.rec_insert(city, value, nodes, index + 1)
elif index == 3:
self.rec_insert(city, value, nodes.children[0], 0)
So what I have observed is that this first if statement actually works. I can insert a root and into the first layer of children.
if nodes.children[index] is None:
Now the problem arises in level 2. Probably because I'm descending wrong.
At the start I can insert normally into layer 2, however as it gets to the right side of the tree it skips the last child in layer 2.
My logic behind this function:
self.rec_insert(city, value, nodes.children[0], 0)
I wanted to make it descend just into the left most child then my other conditional statements will make it shift right as it inserts.
This check:
elif index == 3:
I use it to determine if all the children have been inserted into in a node.
Any help will be appreciated.

Python: Binary Tree Class: Reconstruct with traversals

I am trying to make a function that uses my ListBinaryTree: class to constructs and prints a binary tree based on the inorder and preorder traversals given as input prompts (in string form, eg. Inorder = 213, Preorder = 123). My Binary Tree class is as follows:
class ListBinaryTree:
"""A binary tree class with nodes as lists."""
DATA = 0 # just some constants for readability
LEFT = 1
RIGHT = 2
def __init__(self, root_value, left=None, right=None):
"""Create a binary tree with a given root value
left, right the left, right subtrees
"""
self.node = [root_value, left, right]
def create_tree(self, a_list):
return ListBinaryTree(a_list[0], a_list[1], a_list[2])
def insert_value_left(self, value):
"""Inserts value to the left of this node.
Pushes any existing left subtree down as the left child of the new node.
"""
self.node[self.LEFT] = ListBinaryTree(value, self.node[self.LEFT], None)
def insert_value_right(self, value):
"""Inserts value to the right of this node.
Pushes any existing left subtree down as the left child of the new node.
"""
self.node[self.RIGHT] = ListBinaryTree(value, None, self.node[self.RIGHT])
def insert_tree_left(self, tree):
"""Inserts new left subtree of current node"""
self.node[self.LEFT] = tree
def insert_tree_right(self, tree):
"""Inserts new left subtree of current node"""
self.node[self.RIGHT] = tree
def set_value(self, new_value):
"""Sets the value of the node."""
self.node[self.DATA] = new_value
def get_value(self):
"""Gets the value of the node."""
return self.node[self.DATA]
def get_left_subtree(self):
"""Gets the left subtree of the node."""
return self.node[self.LEFT]
def get_right_subtree(self):
"""Gets the right subtree of the node."""
return self.node[self.RIGHT]
def __str__(self):
return '['+str(self.node[self.DATA])+', '+str(self.node[self.LEFT])+', '+\
str(self.node[self.RIGHT])+']'
So far I have the following:
def reconstruct():
inorder = input("Please enter the inorder sequence:")
preorder = input("Please enter the preorder sequence:")
#root = preorder[0]
#left_bottom = inorder[0]
#right_bottom = inorder[len(inorder)-1]
my_tree = ListBinaryTree(int(preorder[0]))
my_tree.insert_tree_left(int(inorder[0]))
my_tree.insert_tree_right(int(inorder[len(inorder)-1]))
print (my_tree)
But it only works for a tree with 1 or 2 levels:
An example of the output would be:
Call the function
reconstruct()
Prompt:
Please enter the inorder sequence:213
Please enter the preorder sequence:123
Print result:
[1, 2, 3]
How do I change my function so that it can construct a tree with theoretically infinite amount of traversals/ higher levels?
First of all, the posted code does not work as you show: the class has no constructor arguments. Most of all, you need to consult your class materials to see how to reconstruct the tree from the two given orders.
The head of inorder is the root of the tree.
Find this element in the preorder.
Split the preorder at this point: elements before the root
are in its left subtree; elements after are in the right subtree.
Use these to split the inorder similarly.
Recur on each of the left and right subtrees.
Does that get you going?
Let's see about that pseudo-code:
def build_tree(inorder, preorder):
if len(inorder) == 1:
make a one-node tree of this node
return this tree
head = inorder[0]
head_pos = position of head in preorder[]
left_pre = preorder[:head_pos]
right_pre = preorder[head_pos+1:]
left_in = inorder[1:-len(right_pre)]
right_in = inorder[-len(right_pre):]
left_tree = build_tree(left_in, left_pre)
right_tree = build_tree(right_in, right_pre)
make a tree that has
head as its root
left_tree as its left subtree
right_tree as its right subtree
return this tree

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.

Counting nodes in General tree in python

I have created a Tree structure that is not a binary tree and having difficulties in getting the correct node count.
class TreeNode(object):
def __init__(self, name='root', children=None,Parent=[]):
self.Name = name
self.Parents=Parent
self.Children = []
if children is not None:
for child in children:
self.add_child(child.Name)
def __repr__(self):
return self.Name
def add_child(self, node):
self.Children.append(node)
and this is the latest in what I have tried to do in order to count the number of nodes in the tree.
def countNodes(Tree):
for Child in Tree.Children:
return countNodes(Child)+1
return 1
Could someone explain why this doesn't work?
EDIT: I should clarify, When I say doesn't work it gives me a completely wrong count for he number of nodes in my graph.
You countNodes function is not well. A parent node can have two childs, if you put a return statement within the for loop, it will return on the first child count and the second child count will be missing. You need to do something like this:
def countNodes(Tree):
count = 1
for Child in Tree.Children:
count += countNodes(Child)
return count
Just to add #levi has missed an edge case where root is None
so the modified code will be :
def numNodes(root):
if root == None:
return 0
node = 1
for child in root.children:
node = node + numNodes(child)
return node

Categories