Creating a binary tree from a binary sequence in python - python

I am trying to binary create a tree from a binary sequence like "100101"
then i want the tree to be created like this. (Basically 1 means go to the right and 0 means go to the left)
<Root node>
|
1
/
0
/
0
\
1
/
0
\
1
so i did it here is the code:
where the value would be the string sequence (ex value = "1001")
def _inserto(root,value):
for i in value:
if root == None:
root = BSTNode(i)
current = root
elif i == "1":
if current.right is not None:
current.right = BSTNode(i)
current = current.right
else:
current.right = BSTNode(i)
current = current.right
elif i == "0":
if (current.left is not None):
current.left = BSTNode(i)
current = current.left
else:
current.left =BSTNode(i)
current = current.left
return root
Now the problem is that if i want to input another sequence like "01", the tree should look like this
<Root Node>
|
1
/
0
/ \
0 1
\
1
/
0
\
1
, but i am really having a hard time, since my function is going to over-write the old tree.

The problem is with the code dealing with an existing node. If it is present, the code overwrites it with a new BSTNode, losing all the existing nodes under it. What you need is something like:
elif i == "1":
if current.right is None:
current.right = BSTNode(i)
current = current.right
elif i == "0":
if root.left is None:
current.left = BSTNode(i)
current = current.left
This will only allocate a node if there is not one already present, and then set current to this new node.

Related

What time and space complexity am I using with memoized countUnivalTrees problem

I was attempting this challenge but took too long to execute for some inputs. The question is as follows
You are given a binary tree. Return the count of unival sub-trees in the given binary tree. In unival trees, all the nodes, below the root node, have the same value as the data of the root.
My first attempt failed because of the time complexity
def countUnivalTrees(tree):
if tree is None:
return 0
leftCount = countUnivalTrees(tree.left)
rightCount = countUnivalTrees(tree.right)
count = leftCount + rightCount
if isUnivalTree(tree, tree.value):
count += 1
return count
def isUnivalTree(tree, value):
if tree is None:
return True
if tree.value != value:
return False
if tree.left is None and tree.right is None:
return True
return isUnivalTree(tree.left, value) and isUnivalTree(tree.right, value)
It gives the right answer but can take too long to execute for some given inputs.
My Second approach was to memoize what I've seen already.
def countUnivalTrees(root, memoized={}):
if root is None:
return 0
memoized[root] = False
leftCount = countUnivalTrees(root.left, memoized)
rightCount = countUnivalTrees(root.right, memoized)
count = leftCount + rightCount
if root.left is not None and root.right is not None:
if memoized[root.left] and memoized[root.right] and root.left.value == root.right.value and root.value == root.left.value:
memoized[root] = True
count += 1
elif root.left is not None:
if memoized[root.left] and root.value == root.left.value:
memoized[root] = True
count += 1
elif root.right is not None:
if memoized[root.right] and root.value == root.right.value:
memoized[root] = True
count += 1
else:
if isUnivalTree(root, root.value):
memoized[root] = True
count += 1
return count
The isUnivalTree is indentical to the first attempt so I omitted it to not add the extra code. I was able to pass all tests. My plan was to have a time complexity of O(n) and O(n) space. I am having trouble understanding exactly what my complexity would be and if my approach is correct. By correct I mean working exactly how I believe it should be:
step 1: visit each node in the tree
step 2: from leaf to root check current root is unival or not. If it is save the root in memoized and map it to true.
step 3: if current root node has a left and right child node and that node in memoized maps to true meaning it is a unival tree than just check right and left child values to be the same and root value to be the same and is a unival tree memoize the current root and map to true. (also take into account for roots that have only one left child or only one right child and perform those checks as well O(1) operations)
So I'm imagining a big tree with many spanning left and right but with all the same values. Is it true that we are looking at all the nodes once O(n), where n is the number of nodes and then as we pop off the stack memoizing that current node and mapping to true if isUnivalTree and so on.
For some reason I feel like I might be missing a case where I should check if memoized[root.left] = False and if it is then not count it. Not sure really, I never memoized before besides for the fibonacci coding problem so this is new to me.
We can't see the memoization because we don't see your isUnivalTree. But if it is fast, then it is certainly O(n) time because you're only visiting each node a maximum of 2x (once to count trees, once to see if it was marked unival), on one of which you memoize it.
But there is no need to memoize. Just return all of the context that you need in one go. And if that is messier than you want to use, then have a trivial wrapper.
def unival_trees (root):
return _unival_trees_and_meta(root)[0]
def _unival_trees_and_meta(root):
if root.left is None:
if root.right is None:
return (1, True, root.value)
else:
count_right, right_is_unival, right_value = _unival_trees_and_meta(root.right)
if right_is_unival and root.value == right_value:
return (count_right + 1, True, root.value)
else:
return (count_right, False, root.value)
else:
count_left, left_is_unival, left_value = _unival_trees_and_meta(root.left)
if root.right is None:
if left_is_unival and left_value == root.value:
return (count_left + 1, True, root.value)
else:
return (count_left, False, root.value)
else:
count_right, right_is_unival, right_value = _unival_trees_and_meta(root.right)
if left_is_unival and right_is_unival and left_value == right_value and left_value == root.value:
return (count_right + count_left + 1, True, root.value)
else:
return (count_right + count_left, False, root.value)

Time complexity worst case and best case for Djikstra's algo?

Could someone explain the time complexity (worst case and vest case) of the below Djikstra algorithm line by line? I could not find a detailed explanation anywhere, so any help would be appreciated.
def dijkstra(graph,start,pharmacy):
minimumContainmentZones = {}
predecessor = {}
unseenNodes = deepcopy(graph)
infinity = 9999999
path = []
for node in unseenNodes:
minimumContainmentZones[node] = infinity
minimumContainmentZones[start] = 0
while unseenNodes:
minNode = None
for node in unseenNodes:
if minNode is None:
minNode = node
elif minimumContainmentZones[node] < minimumContainmentZones[minNode]:
minNode = node
for childNode, weight in graph[minNode].items():
if weight + minimumContainmentZones[minNode] < minimumContainmentZones[childNode]:
minimumContainmentZones[childNode] = weight + minimumContainmentZones[minNode]
predecessor[childNode] = minNode
unseenNodes.pop(minNode)
currentNode = pharmacy
while currentNode != start:
try:
path.insert(0,currentNode)
currentNode = predecessor[currentNode]
except:
print('Path not reachable')
break
path.insert(0,start)
if minimumContainmentZones[pharmacy] != infinity:
return(pharmacy,minimumContainmentZones[pharmacy],str(path))

how to programming pre / in order traversal without recursion in python

here is my code about postorder_nonrecursive.
I want to know preorder and inorder like this code.
please help me!
def postorder_nonrecursive(self):
if self == None:
return
stack = [[self,0]]
while len(stack) > 0:
node, state = stack[-1]
if state == 2:
yield node
stack.pop()
else:
child = (node.getLeft() if state == 0 else node.getRight())
stack[-1][1] += 1
if child != None:
stack.append([child,0])

Python - Converting an n-ary tree to a binary tree

class Tree:
def __init__(self, new_key):
self.__key = new_key # Root key value
self.__children = [] # List of children
self.__num_of_descendants = 0 # Number of Descendants of this node
# Prints the given tree
def printTree(self):
return self.printTreeGivenPrefix("", True)
# Prints the given tree with the given prefix for the line
# last_child indicates whether the node is the last of its parent"s child
# or not
def printTreeGivenPrefix(self, line_prefix, last_child):
print(line_prefix, end="")
if last_child:
print("â””--> ", end="")
else:
print("|--> ", end="")
print(self.__key)
if len(self.__children) > 0:
next_pre = line_prefix
if last_child:
next_pre += " "
else:
next_pre += "| "
for child_index in range(len(self.__children)-1):
self.__children[child_index].\
printTreeGivenPrefix(next_pre, False)
self.__children[-1].printTreeGivenPrefix(next_pre, True)
def __repr__(self):
return "[" + str(self.__key) + "".join(
[ repr(child) for child in self.__children ]) + "]"
# This static function will load a tree with the format of below:
# [root[child_1][child_2]...[child_n]]
# Each child_i can be a tree with the above format, too
# pos is the position in the given string
#staticmethod
def loadTree(tree_str, pos = 0):
new_node = None
while pos < len(tree_str):
if tree_str[pos] == "[":
pos += 1
new_node = Tree(tree_str[pos])
while pos < len(tree_str) and tree_str[pos + 1] != "]":
pos += 1
child_tree, pos = Tree.loadTree(tree_str, pos)
if child_tree:
new_node.__children.append(child_tree)
new_node.__num_of_descendants += \
1 + child_tree.__num_of_descendants
return new_node, pos + 1
else:
pos += 1
return new_node, pos
def find_largest(self):
if self.__num_of_descendants == 1:
return self.__children[0]
else:
largest_child = self.__children[0]
for child in self.__children:
if child.__num_of_descendants > \
largest_child.__num_of_descendants:
largest_child = child
if child.__num_of_descendants == \
largest_child.__num_of_descendants:
if child.__key > largest_child.__key:
largest_child = child
return largest_child
def convert_to_binary_tree(self):
if self.__num_of_descendants != 0:
if self.__num_of_descendants < 3:
for child in self.__children:
child.convert_to_binary_tree()
if self.__num_of_descendants > 2:
left_child = self.__children[0]
for child in self.__children[1:]:
if len(child.__children) > len(left_child.__children):
left_child = child
elif len(child.__children) == len(left_child.__children):
if child.__key > left_child.__key:
left_child = child
self.__children.remove(left_child)
self.__num_of_descendants -= 1
right_child = self.__children[0]
for child in self.__children[1:]:
if len(child.__children) > len(right_child.__children):
right_child = child
elif len(child.__children) == len(right_child.__children):
if child.__key > right_child.__key:
right_child = child
self.__children.remove(right_child)
self.__num_of_descendants -= 1
print(self.__num_of_descendants)
print(self.__children)
print(left_child)
print(right_child)
#Move remaining children two either left_child or right_child.
while self.__num_of_descendants != 0:
largest_child = self.find_largest()
print(largest_child)
if left_child.__num_of_descendants < \
right_child.__num_of_descendants:
left_child.__children.append(largest_child)
left_child.__num_of_descendants += 1
self.__children.remove(largest_child)
self.__num_of_descendants -= 1
elif left_child.__num_of_descendants > \
right_child.__num_of_descendants:
right_child.__children.append(largest_child)
right_child.__num_of_descendants += 1
self.__children.remove(largest_child)
self.__num_of_descendants -= 1
elif left_child.__num_of_descendants == \
right_child.__num_of_descendants:
if left_child.__key > right_child.__key:
left_child.__children.append(largest_child)
left_child.__num_of_descendants += 1
self.__children.remove(largest_child)
self.__num_of_descendants -= 1
else:
right_child.__children.append(largest_child)
right_child.__num_of_descendants += 1
self.__children.remove(largest_child)
self.__num_of_descendants -= 1
#Now run recursion on left and right binary children.
self.__children.append(left_child)
self.__children.append(right_child)
self.__num_of_descendants = 2
print(self.__children)
for child in self.__children:
child.convert_to_binary_tree()
def main():
tree, processed_chars = Tree.loadTree('[z[y][x][w][v]]]')
tree.convert_to_binary_tree()
tree.printTree()
print(tree)
if __name__ == "__main__":
main()
I have to convert a given tree into a binary tree. If a node in the tree has more than 2 children, I have to assign the child with the most descendants as the left node and the child with the second largest number of descendents as the right child. The remaining children are added as following:
1) Take child with largest number of descendants
2) Add it to Left/Right node. Whichever has fewer children at that time.
*If at any time I need to select the child with the largest number of descendants, but there are two+ with the same number of descendents, I take the one with the larger key value.
I get a print out like this...
2 #Number of 'z' children after left and right node chosen.
[[w], [v]] #Children of 'z'
[y] #Binary left child of 'z'
[x] #Binary right child of 'z'
[w] #This is a bug. It should be choosing 'v' as larger child of 'z' and assigning it to left child 'y'
[v] #This is a bug. see above.
[[y[w]], [x[v]]] #These are the children of node 'z'
â””--> z #schematic of binary tree
|--> y
| â””--> w
â””--> x
â””--> v
[z[y[w]][x[v]]] #final binary tree
DSM's comment helped me see what is going on. After you pick left_child and right_child in the first parts of your convert_to_binary_tree method, you're not removing them from the list of children. This means that later, when you go to add all of the current node's children into new parents, you're adding the left and right children to themselves (or each other). When you recurse into those children, you can end up infinitely looping.
I don't really understand the logic of your left_child and right_child selections, so I don't have fixed code to suggest to you. A quick but ugly fix would be to put a if child in (left_child, right_child): continue statement at the top of the for loop where you're assigning the other children to new parents.
Note that there's another bug in your current code, where the descendent counts for the left and right children will become incorrect. That's because you're not updating the count when you push some of their former siblings into them as children.

Counting number of nodes in a Binary Search Tree

I am trying to print the size of my binary search tree. However, what my code is doing now is printing what level each node is at. I feel as though I am putting my count += 1 in the wrong place or perhaps it might be something else. I was wondering if someone could be an extra set of eyes for me and give me a hint on how I can fix this.
output:
3
3
2
3
3
2
1
expected output:
7
my code:
def BST_size(root, count = 0):
if root is None:
print "size -1 (Null value in root)"
if root is not None:
count += 1
if root.left is not None:
BST_size(root.left, count)
if root.right is not None:
BST_size(root.right, count)
print count
Extra parts:
class Node:
def __init__(self,value):
self.right = None
self.left = None
self.value = value
def BST_Insert(root, node): # root --> root of tree or subtree!
if root.value is None:
root = node # beginning of tree
else:
if root.value > node.value: # go to left
if root.left is None:
root.left = node
else:
BST_Insert(root.left, node)
if root.value < node.value: # go to right
if root.right is None:
root.right = node
else:
BST_Insert(root.right, node)
r = Node(4)
# left
a = Node(2)
b = Node(1)
c = Node(3)
# right
d = Node(8)
e = Node(6)
f = Node(10)
BST_Insert(r, a)
BST_Insert(r, b)
BST_Insert(r, c)
BST_Insert(r, d)
BST_Insert(r, e)
BST_Insert(r, f)
There are two ways to do this.
The easy way is to return the count from each recursive call, instead of just printing it, and increment:
def BST_size(root):
if root is None:
return -1
if root is not None:
if root.left is not None:
return 1 + BST_size(root.left)
if root.right is not None:
return 1 + BST_size(root.right)
def print_BST_size(root):
size = BST_size(root)
if size == -1:
print "size -1 (Null value in root)"
else:
print "size", size
However, that still doesn't work, because you're only traversing the left side or the right side, not both. What you want is:
count = -1
if root is not None:
if root.left is not None:
count += BST_size(root.left)
if root.right is not None:
count += BST_size(root.right)
return count
However, it looks like you're trying to use an accumulator, in tail-recursive style. There's really no point in doing this in Python, because Python doesn't optimize tail calls, but it's a useful skill to learn for other languages and for theoretical reasons, so…
The problem here is that you need the same value to be shared by all of the recursive calls, which means you need a mutable value. So, you can start with [0] instead of 0, and do count[0] += 1 instead of count += 1.
Or you can rearrange your code so that it doesn't use count mutably, and instead passes the updated count from one side down to the other.
Either way, you've got another problem with your code. Your recursive base case is that root is None. But you've also made it a special case, printing -1 instead of 0. You can't have it both ways.
def BST_size(root, count = 0):
if root is None:
return count
return BST_size(root.left, BST_size(root.right, count + 1))
def BST_size(root):
if root is None:
return 0
else:
return BST_size(root.left) + BST_size(root.right) + 1
print "Size is: " + str(BST_size(r))
if root is not None:
count = 1
if root.left is not None:
count += BST_size(root.left, count)
if root.right is not None:
count += BST_size(root.right, count)
return count
Here is a short answer
You have to do tree treversal, where the function returns the number of nodes below + 1 (itself)
Pseudo code:
def counter(t):
rCount = counter(t.right)
lCount = counter(t.left)
return 1 + rCount + lCount
You could use something like this:
def countNodes(root):
count = 1
if root is None:
return -1
if root is not None:
if root.left is not None:
count += countNodes(root.left)
if root.right is not None:
count += countNodes(root.right)
return count
and invoke it like below:
print ("\nCount of Nodes :" + str(countNodes(root)))

Categories