Can this code be improved to implement Binary Expression Tree? - python

For more basic information (for starters)... you may want to read this question:
How to Implement a Binary Tree?
For more information on how to implement a binary tree... you may want to open this site:
http://www.openbookproject.net/thinkcs/python/english2e/ch21.html
The binary operation tree is way different from its father... the Binary Tree. This is the expression tree for the string '(7+3)(5-2):Expression Tree for (7+3)(5-2).
The snippet way way below should do the following...
Read a string
When it encounters '(', then it creates a new node and goes to the left child of the current node
When it encounters any digit, it places the data then goes up
When it encounters an operator '+','-','*','/', then it places the data then goes to the right child of the current node
When it encounters ')', then it backtracks and goes up.
There are few problems with this code that need to be solved...
the int(strng) does not function well in this code: BinaryOperationTree instance has no attribute 'len'
Or maybe you may add your own code to answer this question... If you do this, then you may disregard the code below. Take note that it should print the nodes infix, prefix, and postfix...
class Node:
def __init__ (self, data, currNode):
self.data = data
self.left = None
self.right = None
self.parent = currNode
currNode = self.right
return currNode
class BinaryOperationTree():
def __init__(self):
strng = raw_input('Please enter the operation to turn it into a binary tree.\n')
print strng
def readCharacter(self):
for i in range(-1, str_len, -1):
k = k + 1
if (k >= 2):
j = j * 16
l = 0 #Counter
currNode = Node
while (l <= k - 1):
if isDigit(hexa[l]):
encntrDigit(hexa[l], currNode)
elif isRPar(hexa[l]):
enctrRpar(currNode)
elif isLPar(hexa[l]):
enctrLpar(currNode)
elif isOperator(hexa[l]):
enctrOperator(hexa[1], currNode)
def isDigit(x):
chars = ['0','1','2','3','4','5','6','7','8','9']
if chars in x:
return True
else:
return False
def isRPar(x):
if ')' in x:
return True
else:
return False
def isLPar(x):
if '(' in x:
return True
else:
return False
def isOperator(x):
chars = ['+','-','*','/']
if chars in x:
return True
else:
return False
def encntrDigit(x, currNode):
currNode.data = x
currNode = currNode.parent
return currNode
def enctrRpar(self, currNode):
currNode = currNode.parent
def enctrLPar(self, currNode):
currNode = Node()
def enctrOperator(self, x, currNode):
currNode.data = x
currNode = currNode.parent
#Prints the tree in Pre-Order Format
def preOrder (node):
if (node is not None):
print node.data, "",
preOrder(node.left)
preOrder(node.right)
#Prints the tree in Order Format
def inOrder (node):
if (node is not None):
inOrder (node.left)
print node.data, "",
inOrder (node.right)
#Prints the tree in Post-Order Format
def postOrder (node):
if (node is not None):
postOrder (node.left)
postOrder (node.right)
print node.data, "",
def main():
string = BinaryOperationTree()
string.readCharacter()
main()

Related

Python recursive path finder for binary tree

I'm trying to write a recursive function in python that given a binary tree and a node returns a string containing directions to the node. I've got close but my final return statement gives me the path plus the node (I don't need the node) i.e LRLR4.
here is my code so far:
class Tree:
def __init__(self):
self.root = None
self.left = None
self.right = None
def join(item: object, left: Tree, right: Tree):
tree = Tree()
tree.root = item
tree.left = left
tree.right = right
return tree
def path(tree: Tree, node: str, out: str=""):
if not tree:
return ""
if tree.root == node:
return tree.root
res = path(tree.left, node)
if res:
return "L" + res
res = path(tree.right, node)
if res:
return "R" + res
Is there a way I can implement this without the node on the end of the string output?
Edit: added all actual code and the tree in question contains single letter strings for each node.
To write path -
def path(tree, target):
if not tree:
return ""
elif target < tree.root:
return "L" + path(tree.left, target)
elif target > tree.root:
return "R" + path(tree.right, target)
else:
return "" # tree.root equal to target; don't return node
We can make some more improvements to your Tree class though. See these assignments in join?
def join(item: object, left: Tree, right: Tree):
tree = Tree()
tree.root = item
tree.left = left
tree.right = right
return tree
It would be better if the Tree constructor takes these values as arguments -
class Tree:
def __init__(self, root, left = None, right = None):
self.root = root
self.left = left
self.right = right
def join(item, left, right):
return Tree(item, left, right) # pass as arguments
Now the join function is redundant and can be removed -
class Tree:
def __init__(self, root, left = None, right = None):
self.root = root
self.left = left
self.right = right
# no more need for `join`
Given mytree -
# g
# / \
# / \
# d m
# / \ / \
# b f j q
# / \
# a k
mytree = \
Tree("g",
Tree("d", Tree("b", Tree("a")), Tree("f")),
Tree("m", Tree("j", None, Tree("k")), Tree("q"))
)
print(path(mytree, "f")) # LR
print(path(mytree, "k")) # RLR
print(path(mytree, "q")) # RRR

question on serialization and deserialization in binary tree

There is this problem asked by Google to design an algorithim to serialize and deserialize binary tree. I found one of the solutions online. The part i don't really understand is why the condition is necessary at line 20, where "if node == None:", self.root = Node(value) ? Because afterall this program will prompt the user to input nodes in the form eg: 1,3,5 in order for the program to work so therefore there won't be a case where node =none because user input is necessary? Am I misunderstanding something else here?
class Node:
def __init__(self, value):
self.left = None
self.right = None
self.value = value
class Tree:
def __init__(self):
self.root = None
def addNode(self, node, value): #Why when node==None, self.root= Node(value)?
if node == None:
self.root = Node(value)
else:
if value < node.value:
if not node.left:
node.left = Node(value)
else:
self.addNode(node.left, value)
else:
if not node.right:
node.right = Node(value)
else:
self.addNode(node.right, value)
def serialize(root):
values = []
def serializer(node):
if not node:
values.append('?')
else:
values.append(str(node.value))
serializer(node.left)
serializer(node.right)
serializer(root)
return ','.join(values)
def deserialize(s):
values = iter(s.split(','))
def deserializer():
val = next(values)
if val == '?':
return None
else:
node = Node(int(val))
node.left = deserializer()
node.right = deserializer()
return node
return deserializer()
if __name__ == '__main__':
# Read input, numbers separated by commas
numbers = [int(n) for n in input().split(',')]
theTree = Tree()
for number in numbers:
theTree.addNode(theTree.root, number)
s1 = serialize(theTree.root)
s2 = serialize(deserialize(s1))
print(s1)
print(s2)
assert s1 == s2
In this line, when first number is entered in the tree, root will be None
for number in numbers:
theTree.addNode(theTree.root, number)
Hence, line 20 is needed.

Question on argument in functions for deserializing the string back into tree in Python

The question that I am asking here is based on www.dailycodingproblem.com
question 3:
"Given the root to a binary tree, implement serialize(root), which serializes the tree into a string, and deserialize(s), which deserializes the string back into the tree."
The code below is one of the solutions that I found and the question I want to ask is:-
For the deserialize function in line 42, when I pass an argument such as
def deserializer(node): which is followed by return deserializer(node), the output says "node not defined error" if I input any numbers eg: 1,3,2.
However, it works when I leave out the argument part empty that is def deserializer() followed by return deserializer()?
Your help would be much appreciated!
#must create a constructor every time we create a class eg: def __init__(self)
class Node:
def __init__(self, v):
self.left = None #none = empty state
self.right = None
self.value = v
class Tree:
def __init__(self):
self.root = None
def addNode(self, node, v1):
if node == None:
self.root = Node(v1)
#argument in Node need not have to be v
else:
if v1 < node.value:
#if 2nd value less than 1st value for example?
if not node.left:
node.left = Node(v1) #will not update value
else:
#if it is node.left,update value
self.addNode(node.left, v1)
else:
if not node.right:
node.right = Node(v1)
else:
self.addNode(node.right, v1)
def deserialize(s):
values = iter(s.split(','))
def deserializer(): #why putting def deserializer(node) gives me "node undefined error"?)
val = next(values)
if val == '?':
return None
else:
node = Node(int(val))
node.left = deserializer()
node.right = deserializer()
return node
return deserializer() #why putting return deserializer(node) gives me "node undefined error"?)
if __name__ == '__main__':
# Read input, numbers separated by commas
numbers = [int(n) for n in input().split(',')]
theTree = Tree()
for number in numbers:
theTree.addNode(theTree.root, number)
s2 = serialize(deserialize(s1))
print(s2)

Trie Implementation in Python -- Print Keys

I Implemented a Trie data structure using python, now the problem is it doesn't display the keys that Trie is stored in its data structure.
class Node:
def __init__(self):
self.children = [None] * 26
self.endOfTheWord = False
class Trie:
def __init__(self):
self.root = self.getNode()
def getNode(self):
return Node()
def charToIndex(self ,ch):
return ord(ch) - ord('a')
def insert(self ,word):
current = self.root
for i in range(len(word)):
index = self.charToIndex(word[i])
if current.children[index] is None:
current.children[index] = self.getNode()
current = current.children[index]
current.endOfTheWord = True
def printKeys(self):
str = []
self.printKeysUtil(self.root ,str)
def printKeysUtil(self ,root ,str):
if root.endOfTheWord == True:
print(''.join(str))
return
for i in range(26):
if root.children[i] is not None:
ch = chr(97) + chr(i)
str.append(ch)
self.printKeysUtil(root.children[i] ,str)
str.pop()
You could perform a pre-order traversal of the nodes, and wherever you find an end-of-word marker, you zoom up to the root, capturing the letters as you go, in order to get the full word... except that to accomplish this, you would need to store the parent node in each node.
def printKeysUtil(self ,root ,str):
if root.endOfTheWord == True:
print(''.join(str))
return
for i in range(26):
if root.children[i] is not None:
ch = chr(97+i)
str.append(ch)
self.printKeysUtil(root.children[i] ,str)
str.pop()

python create a binary search tree using existing function

I'm practicing creating a balanced binary search tree in python.
I already have these below, any idea on how to create a balance_bst funtion that passed a list of unique values that are
sorted in increasing order. It returns a reference to the root of a well-balanced binary search tree:
class LN:
def __init__(self,value,next=None):
self.value = value
self.next = next
def list_to_ll(l):
if l == []:
return None
front = rear = LN(l[0])
for v in l[1:]:
rear.next = LN(v)
rear = rear.next
return front
def str_ll(ll):
answer = ''
while ll != None:
answer += str(ll.value)+'->'
ll = ll.next
return answer + 'None'
# Tree Node class and helper functions (to set up problem)
class TN:
def __init__(self,value,left=None,right=None):
self.value = value
self.left = left
self.right = right
def height(atree):
if atree == None:
return -1
else:
return 1+ max(height(atree.left),height(atree.right))
def size(t):
if t == None:
return 0
else:
return 1 + size(t.left) + size(t.right)
def is_balanced(t):
if t == None:
return True
else:
return abs(size(t.left)-size(t.right)) <= 1 and is_balanced(t.left) and is_balanced(t.right)
def str_tree(atree,indent_char ='.',indent_delta=2):
def str_tree_1(indent,atree):
if atree == None:
return ''
else:
answer = ''
answer += str_tree_1(indent+indent_delta,atree.right)
answer += indent*indent_char+str(atree.value)+'\n'
answer += str_tree_1(indent+indent_delta,atree.left)
return answer
return str_tree_1(0,atree)
How do write the balance_bst?
def balance_bst(l):
Here is what I did:
def build_balanced_bst(l):
if l == None:
return None
else:
middle = len(l) // 2
return TN(l[middle],
build_balanced_bst(l[:middle]),
build_balanced_bst(l[middle + 1:]))
It gives me:
IndexError: list index out of range
How do I fix it?
I'm not going to write it for you since that's not what SO is about, but here's the general idea. Since the list is already sorted, the root should be the element in the middle of the list. Its left child will be the root of the balanced tree consisting of the elements to the left of the root in the list, and the right sub-tree will be the rest.

Categories