Reconstructing a binary tree from infix and prefix expressions [python] - python-3.x

Ive been spending hours on trying to figure out how to do this, I know the function "buildtree" has to be called recursively to draw but I just cant figure it out, I just need a spoon-fed answer which I can then study, I have tried to do this for so long its just not within my capabilities cause I cant understand the logical flow of things. (Sad thing is I know this will only take a few lines of code)
from ListBinaryTree import ListBinaryTree
def buildtree(left_inorder, left_preorder, right_inorder, right_preorder, root, tree):
#dont know what to do.
def main():
print("Binary Tree reconstructed by glee598:")
inorder_seq = input("Please enter the inorder sequence: ")
preorder_seq = input("Please enter the preorder sequence: ")
root = preorder_seq[0]
root_inorder_index = inorder_seq.find(root)
left_inorder = inorder_seq[:root_inorder_index]
right_inorder = inorder_seq[root_inorder_index+1:]
left_preorder = preorder_seq[1:preorder_seq.find(left_inorder[0])+1]
right_preorder = preorder_seq[preorder_seq.find(left_inorder[0])+1:]
tree = ListBinaryTree(root)
buildtree(left_inorder, left_preorder, right_inorder, right_preorder, root, tree)
main()
The ListBinaryTree class:
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])+']'
Objective:

I think you've just about got it, you've just put too much of your logic in the setup code and not realized that the recursive code is going to be the same thing.
It will be a lot easier if you change the API of your recursive buildtree function to simply take the whole inorder and preorder sequences and return a tree built out of them.
def buildtree(inorder, preorder):
root_val = preorder[0]
left_size = inorder.index(root_val) # size of the left subtree
if left_size > 0:
left = buildtree(inorder[:left_size], preorder[1:left_size+1])
else:
left = None
if (left_size + 1) < len(inorder):
right = buildtree(inorder[left_size+1:], preorder[left_size+1:])
else:
right = None
return ListBinaryTree(root_val, left, right)

Related

code should not return any node object(Element)

https://gist.github.com/manaidu-2002/3f7eb60b8521201eba6548ca23cec053
Code returning Node Object(Element), please check the test cases and help me with this
"""Add a couple methods to our LinkedList class,
and use that to implement a Stack.
You have 4 functions below to fill in:
insert_first, delete_first, push, and pop.
Think about this while you're implementing:
why is it easier to add an "insert_first"
function than just use "append"?"""
class Element(object):
def __init__(self, value):
self.value = value
self.next = None
class LinkedList(object):
def __init__(self, head=None):
self.head = head
def append(self, new_element):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = new_element
else:
self.head = new_element
def insert_first(self, new_element):
"Insert new element as the head of the LinkedList"
new_element.next = self.head
self.head = e_insert
def delete_first(self):
"Delete the first (head) element in the LinkedList as return it"
temp = self.head
if temp == None:
return None
s= temp
self.head = temp.next
return s
class Stack(object):
def __init__(self,head=None):
self.ll = LinkedList(head)
def push(self, new_element):
"Push (add) a new element onto the top of the stack"
temp = self.ll.head
while temp.next :
temp = temp.next
temp.next = new_element
def pop(self):
"Pop (remove) the first element off the top of the stack and return it"
if self.ll.head.next == None :
temp = self.ll.head
e= temp
temp = None
return e
elif self.ll.head.next:
temp = self.ll.head
while temp.next.next:
temp = temp.next
e= temp.next
temp.next = None
return e
return None
# Test cases
# Set up some Elements
e1 = Element(1)
e2 = Element(2)
e3 = Element(3)
e4 = Element(4)
# Start setting up a Stack
stack = Stack(e1)
# Test stack functionality
stack.push(e2)
stack.push(e3)
print(stack.pop().value)
print(stack.pop().value)
print(stack.pop().value)
print(stack.pop())
stack.push(e4)
print(stack.pop().value)
First of all, there is an unused name reference in your code: e_insert. This should read new_element.
The main issue is that your Stack class is not re-using the code you already have in your LinkedList class. In the new code you have written there are several mistakes in how you deal with next, but taking a step back, you are making a critical mistake in thinking that the top of the stack should be at the tail of the linked list, but that is very inefficient. The top of the stack should be at the head of the linked list. It is at that side that you can easily remove and insert elements without having to iterate the list.
So take these points into consideration:
Reuse the code you already have for LinkedList. In other words, call the methods defined on the LinkedList class.
The top of the stack is at the head of the linked list.
That means the Stack class can be as simple as this:
class Stack(LinkedList):
def __init__(self, head=None):
self.ll = LinkedList(head)
def push(self, new_element):
self.ll.insert_first(new_element)
def pop(self):
return self.ll.delete_first()

Traversal of a binary tree: i cannot get right output in python

I am typing pre-order traversal and the output is just '1-'; I have looked through several other threads on this site but cannot seem to find my mistake. Any hints or suggestions would be appreciated!
class Node(object):
def __init__(self, value):
self.number = value
self.left = None
self.right = None
class binarytree(object):
def __init__(self, root):
self.root = Node(root)
def print_traversal(self, direction, start):
if direction == 'pre_order':
return self.pre_order(start, '')
def pre_order(self, start, traversal):
if start:
traversal += (str(start.number) + '-' )
self.pre_order(start.left, traversal)
self.pre_order(start.right, traversal)
return traversal
# main function
tree1 = binarytree(1)
tree1.root.left = Node(2)
tree1.root.right = Node(3)
tree1.root.left.left = Node(4)
tree1.root.left.right = Node(5)
tree1.root.right.left = Node(6)
print(tree1.print_traversal('pre_order', tree1.root))```
The line
traversal += (str(start.number) + '-' )
assigns a new value to the local variable traversal; it does not modify the string already in traversal. Thus, the changes made in the recursive calls are never seen at the level above where they're made.

Most efficient way to query in a data tree that does not have proper indexing

Pardon me if the terminology of the title is wrong. Let me illustrate what I mean:
I have a data tree for a basic educational course. Every node holds 2 values(apart from children and parent data): ID and a bool value. I can not change the ID value since I am fetching it from an API so I can not form my data tree as a binary tree. That is what I mean by "does not have proper indexing".
BTW: ID is random.
As you can see, I am structuring my tree with a hierarchy. Courses are supersets of episodes and episodes are supersets of topics.
My question:
I want to gather some data from a specific topic node. I know it is a topic node and I know its id. How do I find that node to get some data out of it most efficiently?
When I researched about tree data structures, they usually index their nodes with some sort of rule (ex: binary trees), I am not sure I can do that since I want to preserve the hierarchy of data types. If there is a way that I can both keep some sort of indication of hierarchy and order my trees for many efficient queries. I am happy to do that. I don't want to brute force if possible
You can combine the usual Node class approach with a dictionary which you maintain at tree instance level.
For instance:
class Node:
def __init__(self, id, name, boolval):
self.id = id
self.name = name
self.boolval = boolval
self.children = []
def tolist(self): # utility method for simple visualisation
if not self.children:
return [self.name]
else:
return [self.name, [child.tolist() for child in self.children]]
class Tree:
def __init__(self):
self.dict = dict() # this will map id to node
self.root = None
def append(self, id, name, boolval, parentid=""):
node = Node(id, name, boolval)
self.dict[id] = node
if self.root:
parent = self.get(parentid)
parent.children.append(node)
else:
self.root = node
def get(self, id):
return self.dict[id]
def tolist(self):
if not self.root:
return
return self.root.tolist()
# demo use:
tree = Tree()
tree.append("ab12", "Tree", False)
tree.append("ab13", "Physics", False, "ab12")
tree.append("a4d5", "Math", False, "ab12")
tree.append("524d", "Section A", False, "a4d5")
# ...etc
print(tree.tolist())
If you need to know from a given node what its hierarchy is, then add parent references:
class Node:
def __init__(self, id, name, boolval):
self.id = id
self.name = name
self.boolval = boolval
self.children = []
self.parent = None
def path(self):
if self.parent:
return self.parent.path() + [self.id]
return [self.id]
def tolist(self): # utility method for simple visualisation
if not self.children:
return [self.name]
else:
return [self.name, [child.tolist() for child in self.children]]
class Tree:
def __init__(self):
self.dict = dict() # this will map id to node
self.root = None
def append(self, id, name, boolval, parentid=""):
node = Node(id, name, boolval)
self.dict[id] = node
if self.root:
parent = self.get(parentid)
parent.children.append(node)
node.parent = parent
else:
self.root = node
def get(self, id):
return self.dict[id]
def tolist(self):
if not self.root:
return
return self.root.tolist()
# demo use:
tree = Tree()
tree.append("ab12", "Tree", False)
tree.append("ab13", "Physics", False, "ab12")
tree.append("a4d5", "Math", False, "ab12")
tree.append("524d", "Section A", False, "a4d5")
# ...etc
print(tree.tolist())
print(tree.get("524d").path()) # ['ab12', 'a4d5', '524d']

Binary Tree implementation with Separate class for node and tree

I am new to Python and data structures. While learning binary tree, I found all the available implementations have the methods of the tree inside the node class.
But I want to implement it differently, where along with the Node class, there will be a Binary tree class, which will contain the methods of the Binary tree.
This is the code I came up with, but it raises an error with the arguments I am passing to the functions insertleft() and insertright().
class Node():
def __init__(self, arg):
self.left = None
self.right = None
self.data = arg
class Bt():
def __init__(self, root):
self.root = root
def insertleft(temp.left, data):
if (temp.left == None):
temp.left.data = data
elif(data<temp.left.data):
t1 = temp.left
insertleft(t1.left, data)
elif(data>temp.left.data):
t1 = temp.left
insertright(t1.left, data)
def insertright(temp.right, data):
if (temp.right == None):
temp.right.data = data
elif(data<temp.right.data):
t1 = temp.right
insertleft(t1.right, data)
elif(data>temp.right.data):
t1 = temp.right
insertright(t1.right, data)
def insert(self, data):
temp = self.root
if(temp.data = None):
temp.data = data
elif(data<temp.data):
insertleft(temp.left, data)
elif(data>temp.data):
insertright(temp.right, data)
r = Bt()
r.root = Node(5)
r.insert(4)
r.insert(6)
These is the error I received:
def insertleft(temp.left, data):
^
SyntaxError: invalid syntax
I am not sure what the right syntax should be. Thanks in advance for your help
When you define a function, you also define the parameters you will be accepting. Inside a class though, as long as the method is not static or a class method, the first parameter should be self or a variable that represents the instanciated object itself.
In your case, you are already passing the value of temp.left and temp.right when calling the function. Changing the function definitions to just use temp should work just fine. Or even more readible, node since that is what you are actually referring to.
Your insertleft and insertright functions do the same thing as insert, and including them is not necessary. Just modify the insert function to do it all.
Here's what the end result should resemble:
class Node():
def __init__(self, arg):
self.left = None
self.right = None
self.data = arg
class Bt():
def __init__(self, root=None): #Added default value
self.root = Node(root)
def insert(self, data):
if self.root.data is None:
self.root.data = data #Set the root data if it doesn't exist.
else:
self._insert(self.root, data) #Prime the helper function with root node
def _insert(self, node, data): #Insert helper function to do the insertion
if data < node.data: #Check if data needs to be inserted on the left
if node.left is None: #Set left node if it doesn't exist
node.left = Node(data)
else: #Else let the left node decide where it goes as a child
self._insert(node.left, data)
else: #Else data needs to be inserted on the right
if node.right is None: #Set right node if it doesn't exist
node.right = Node(data)
else: #Else let the right node decide where it goes as a child
self._insert(node.right, data)
r = Bt(5)
r.insert(4)
r.insert(6)
Now you're just missing functions to print the Tree and Data... and accessing the data.
Each Node in the binary search tree is considered as a another binary search tree. Hence we don't need to create a separate class for node.

binary search tree - recursive insertion python

I'm trying to correctly construct a binary search tree with a recursive insert function that will allow me to initialize a tree and continue to add nodes (stems). Here is the code that I've done so far (newer to coding, so probably way too wordy):
class Binary_Search_Tree:
class __BST_Node:
def __init__(self, value):
self.value = value
self.right_child = None
self.left_child = None
def __init__(self):
self.__root = None
self.__height = 0
self.value = None
def _recursive_insert(self, value):
new_stem = Binary_Search_Tree.__BST_Node(value)
if self.__root is None:
self.__root = new_stem
self.__root.value = new_stem.value
else:
if self.__root.value > new_stem.value:
if self.__root.right_child is None:
self.__root.right_child = new_stem
self.__root.right_child.value = new_stem.value
else:
self.__root.right_child._recursive_insert(self.__root, value)
else:
if self.__root.left_child is None:
self.__root.left_child = new_stem
self.__root.left_child.value = new_stem.value
else:
self.__root.left_child._recursive_insert(self.__root, value)
def insert_element(self, value):
element_to_insert = self._recursive_insert(value)
return element_to_insert
I then try to add values to this new tree in the main method:
if __name__ == '__main__':
new = Binary_Search_Tree()
new.insert_element(23)
new.insert_element(42)
new.insert_element(8)
new.insert_element(15)
new.insert_element(4)
new.insert_element(16)
The error that I keep getting is: '__BST_Node' object has no attribute '_recursive_insert' This pops up after inserting the first element, so I'm guessing the error occurs somewhere in the else statement. If anyone can figure out where my error is or has any tips on how to make this code more readable/user friendly, I'd be appreciative!
The issue is with this line:
self.__root.right_child._recursive_insert(self.__root, value)
As well as this:
self.__root.left_child._recursive_insert(self.__root, value)
You've defined _recursive_insert to be a method of Binary_Search_Tree, but you're calling it with an instance of __BST_Node, in self.__root.xxxxx_child._recursive_insert, where xxxx_child is an instance of BST_Node.
In fact, your entire _recursive_insert function leaves something to be desired. You're not returning anything from it, but you are assigning it's (non-existent) return value to something in insert_element.
Fixed code:
def _recursive_insert(self, root, value):
new_stem = Binary_Search_Tree.__BST_Node(value)
if root is None:
root = new_stem
else:
if root.value < new_stem.value:
if root.right_child is None:
root.right_child = new_stem
else:
root = self._recursive_insert(root.right_child, value)
elif root.value > new_stem.value:
if root.left_child is None:
root.left_child = new_stem
else:
root = self._recursive_insert(root.left_child, value)
return root
def insert_element(self, value):
self.__root = self._recursive_insert(self.__root, value)
return element_to_insert
Your function did not return an updated root
Your function does not handle a case when the value being inserted would be equal to an existing value, causing spurious entries.
With each recursive call, your function was being passed the same values, so it would not be able to know what to do. A new parameter for the node must be passed across calls. This makes it possible to establish a base case and return.

Resources