Reconstructing a tree using inorder and preorder traversals in Python - python

I need to make a function that builds a tree from a preorder and inorder traversal, but I'm not sure where I should put the MakeNode and recursive calls to construct the tree properly.
Assuming inorder and preorder are both a list of ints, is the following algorithm correct to reconstruct the tree using the traversals?
def build(preorder, inorder):
root = preorder[0]
left subtree = inorder[:root-1]
right subtree = inorder[root+1:]
If so - How can one take that and construct a heap (ArrayHeap) using that algorithm recursively?
I have a class designed to construct nodes and then I can simply use heap.add(node) to create the heap.
Say my class to build a node is named "MakeNode" and is constructed as follows (for syntax purposes):
Class MakeNode():
def __init__(self, character, left=None, right=None):
To create the root node I would need to edit the function like this:
def build(preorder, inorder, heap):
root = preorder[0]
node = MakeNode(root) # Creating root node here
heap.add(node) # Adding to heap
left subtree = inorder[:root-1]
right subtree = inorder[root+1:]
But how should I use recursion to build the rest of the tree?
I can incorporate the left and right preorder for ordering purposes by doing this:
def build(preorder, inorder, heap):
root = preorder[0]
node = MakeNode(root)
heap.add(node)
left subtree = inorder[:root-1]
# order of left subtree = preorder[1:1+left subtree]
right subtree = inorder[root+1:]
# order of right subtree = preorder[root+1:]
I don't really know how to incorporate the recursive calls to build the tree or what exactly to put for the left or right parameters when doing so.
If anybody has any suggestions I would appreciate them, and I'm sorry if I've been unclear.

What you need to do is add the root of the pre-ordered list to the tree, and removing it from preorder list. Split the in order list as you are doing, then passing both the left and right branches recursively. Keep adding the first element of pre-order to the left of the previous node unless left_subtree is empty, then you need to add it to the right.
This is python code (already tested):
class Tree():
def __init__(self, inorder, preorder):
self.root = preorder[0]
lt = inorder[:inorder.index(self.root)]
rt = inorder[inorder.index(self.root) + 1:]
self.build(self.root, lt, rt, preorder[1:])
def build(self, last_node, left_subtree, right_subtree, preorder):
left_preorder = [node for node in preorder if node in left_subtree]
right_preorder = [node for node in preorder if node in right_subtree]
if len(left_subtree) > 0:
last_node.left = left_preorder[0]
lt = left_subtree[:left_subtree.index(last_node.left)]
rt = left_subtree[left_subtree.index(last_node.left) + 1:]
self.build(last_node.left, lt, rt, left_preorder)
if len(right_subtree) > 0:
last_node.right = right_preorder[0]
lt = right_subtree[:right_subtree.index(last_node.right)]
rt = right_subtree[right_subtree.index(last_node.right) + 1:]
self.build(last_node.right, lt, rt, right_preorder)

From http://www.cse.hut.fi/en/research/SVG/TRAKLA2/tutorials/heap_tutorial/taulukkona.html, you have:
parent(i) = i/2
left(i) = 2i
right(i) = 2i+1
so you can define a class:
class ArrayHeapNode:
def __init__(self, elements, index):
self.elements = elements
self.index = index
def left(self):
next = self.index * 2
if next >= len(self.elements):
return None
return ArrayHeapNode(self.elements, next)
def right(self):
next = (self.index * 2) + 1
if next >= len(self.elements):
return None
return ArrayHeapNode(self.elements, next)
def value(self):
return self.elements[self.index]
def set_value(self, _value):
self.elements[self.index] = _value
This gives you a class that can then function as a tree on an array representation of a binary heap according to the article. If there is no element in that branch, None is returned.
You can now create tree traversal algorithms (https://en.wikipedia.org/wiki/Tree_traversal):
def inorder_traversal(node, action):
if not node: return
inorder_traversal(node.left(), action)
action(node.value())
inorder_traversal(node.right(), action)
def preorder_traversal(node, action):
if not node: return
action(node.value())
preorder_traversal(node.left(), action)
preorder_traversal(node.right(), action)
These will also work with a traditional binary tree node:
class BinaryTreeNode:
def __init__(self, value, left, right):
self._value = value
self._left = left
self._right = right
def left(self):
return self._left
def right(self):
return self._right
def value(self):
return self._value
def set_value(self, _value):
self._value = _value
Now, you can make the traversal algorithms more flexible and python-like by doing:
def inorder(node):
if node:
for item in inorder(node.left()):
yield item
yield node.value()
for item in inorder(node.right()):
yield item
This allows you to write things like:
for item in inorder(tree):
print item
You can then count the elements from the node by doing:
n = sum(1 for e in inorder(root))
This then allows you to create an empty array capable of holding n elements for the elements in the heap:
elements = [0 for x in range(n)]
or combined:
elements = [0 for x in inorder(root)]
heap = ArrayHeapNode(elements, 0)
Now, you can iterate over both trees at the same time using:
for a, b in zip(inorder(root), inorder(heap)):
b = a
This should then assign all elements in the binary tree (root) to the correct elements in the array heap (heap) using inorder traversal. The same can be done by implementing a preorder function.
NOTE: I have not tested this code.

def pre_order(node):
print node #pre order ... print ourself first
pre_order(node.left)
pre_order(node.right)
def post_order(node):
post_order(node.left)
post_order(node.right)
print node # post order print self last...
def in_order(node):
in_order(node.left)
print node #in order ... between its children
in_order(node.right)
if you have any one of these you should be able to reproduce the tree
assume we have a tree like this
0
1 2
3 4 5 6
our traversals would be
0,1,3,4,2,5,6 #pre order
3,1,4,0,5,2,6 #in order
so from this we know that
zero is our root
3 is our left most deepest node
6 is our right most deepest node
0
...
3 6
our left over nodes are
1,4,2,5 # preorder
1,4,5,2 # in-order
from this we know that
1 is a child of zero
1 is the next level leftmost node
2 is the next level rightmost node
so we now have
0
1 2
3 6
leaving us with
4,5 # pre order
4,5 # in order
from this we know that 4 is a child of 1, and therefore 5 must be a child of 2 ...
now write a function that does all that
this article may help
http://leetcode.com/2011/04/construct-binary-tree-from-inorder-and-preorder-postorder-traversal.html

Related

How do I find the maximum depth of a tree?

I have a tree data structure, defined as below:
class Tree(object):
def __init__(self, name='ROOT', children=None):
self.name = name
self.children = []
if children is not None:
for child in children:
self.add_child(child)
def __repr__(self):
return self.name
def add_child(self, node):
assert isinstance(node, Tree)
self.children.append(node)
I need to write a function to find the depth of the tree. Here is the function I wrote (takes a Tree as input, and returns an integer value as output), but it is not giving the right answer:
def depth(tree):
count = 1
if len(tree.children) > 0:
for child in tree.children:
count = count + 1
depth(child)
return count
How do I correct it?
While your depth(child) does do the recursive call, it does not do anything with the return value (the depth). You seem to be simply counting the nodes at a given level and calling that the depth (it's really the width).
What you need is something like (pseudo-code):
def maxDepth(node):
# No children means depth zero below.
if len(node.children) == 0:
return 0
# Otherwise get deepest child recursively.
deepestChild = 0
for each child in node.children:
childDepth = maxDepth(child)
if childDepth > deepestChild:
deepestChild = childDepth
# Depth of this node is one plus the deepest child.
return 1 + deepestChild
How about you just do a max of all the depth on each node recursively?
def max_depth(self, depth=0):
if not self.children:
return depth
return max(child.max_depth(depth + 1) for child in self.children)

Counting nodes in a binary tree recursively

I have to count nodes in a binary tree recursively. I'm new to python and can't find any solution for my problem to finish my code.
This is what I have already tried. As you can see it is not complete, and I can't figure out where to go.
class Tree:
def __init__(self, root):
self.root = root
def add(self, subtree):
self.root.children.append(subtree)
class Node:
def __init__(self, value, children=None):
self.value = value
self.children = children if children is not None else []
def check_root(tree):
if tree.root is None:
return 0
if tree.root is not None:
return count_nodes(tree)
def count_nodes(tree):
if tree.root.children is not None:
j = 0
for i in tree.root.children:
j = 1 + count_nodes(tree)
return j
print(count_nodes(Tree(None))) # 0
print(count_nodes(Tree(Node(10)))) # 1
print(count_nodes(Tree(Node(5, [Node(6), Node(17)])))) #3
With every new step I'm getting different error. E.g. with this code I have exceeded maximum recursion depth.
Thank you for your time reading this. Any hint or help what to do next would be greatly appreciated.
I would start by passing the root node to the count_nodes function -
print(count_nodes(Tree(None)).root) # 0
print(count_nodes(Tree(Node(10))).root) # 1
print(count_nodes(Tree(Node(5, [Node(6), Node(17)]))).root) #3
or make a helper function for that.
Then the count_nodes function can simply look like this
def count_nodes(node):
return 1 + sum(count_nodes(child) for child in node.children)
EDIT: I have just noticed, you can have a None root, this means, you should also handle that:
def count_nodes(node):
if node is None:
return 0
return 1 + sum(count_nodes(child) for child in node.children)
And if you really want to handle tree or node in one function, you can make it a bit uglier:
def count_nodes(tree_or_node):
if isinstance(tree_or_node, Tree):
return count_nodes(tree_or_node.root)
if tree_or_node is None:
return 0
return 1 + sum(count_nodes(child) for child in tree_or_node.children)
and then you can call it like you originally did.
Your problem is that you're counting the same tree infinitely. Take a look at this line:
j = 1 + count_nodes(tree)
An Easy Way:
Lets assume, A is a binary tree with children or nodes which are not NULL. e.g.
3
/ \
7 5
\ \
6 9
/ \ /
1 11 4
Now in order to count number of nodes, we have a simple workaround.
Recursive Method: >>> get_count(root)
For a binary tree, the basic idea of Recursion is to traverse the tree in Post-Order. Here, if the current node is full, we increment result by 1 and add returned values of the left and right sub-trees such as:
class TestNode():
def __init__(self, data):
self.data = data
self.left = None
self.right = None
Now we move forward to get the count of full nodes in binary tree by using the method below:
def get_count(root):
if (root == None):
return 0
res = 0
if (root.left and root.right):
res += 1
res += (get_count(root.left) +
get_count(root.right))
return res
At the end, in order to run the code, we'll manage a main scope:
Here we create our binary tree A as given above:
if __name__ == '__main__':
root = TestNode(3)
root.left = TestNode(7)
root.right = TestNode(5)
root.left.right = TestNode(6)
root.left.right.left = TestNode(1)
root.left.right.right = TestNode(4)
Now at the end, inside main scope we will print count of binary tree nodes such as:
print(get_Count(root))
Here is the time complexity of this recursive function to get_count for binary tree A.
Time Complexity: O(n)

Building a Tree with inorder and preorder traversal in Python3.x

I am trying to build a tree using the preorder and inorder traversals (list of ints). Here is what I have so far:
def build(preorder, inorder, heap): # Builds tree with the inorder and preorder traversal
if len(preorder) == 0:
return None
root = preorder[0] # Root is first item in preorder
k = root
left_count = inorder[(k-1)] # Number of items in left sub-tree
left_inorder = inorder[0:left_count]
left_preorder = preorder[1:1+left_count]
right_inorder = inorder[1+left_count:]
right_preorder = preorder[1+left_count:]
return [root, build(left_preorder, left_inorder), build(right_preorder, right_inorder)]
I believe this algorithm is correct, although I could be wrong.
My question is this - at what point do I insert the items into the tree?
I have a class written to handle this, I'm just not sure where to insert this call, as the function will operate recursively. Any suggestions for how I should insert the nodes into the tree would be appreciated.
class heap:
def __init__(self,the_heap):
self.heap = the_heap
def getChildren(self,value):
n = self.heap.index(value)
return self.heap[2*n+1],self.heap[2*n+2] # i think ...
def getParent(self,value):
n = self.heap.index(value)
if n == 0: return None
return self.heap[math.floor(n-1/2.0) ] # i think ...
def traverse(self):
#do your traversal here just visit each node in the order you want
pass
the_heap = heap(range(100))
print the_heap.getChildren(2)
print the_heap.getParent(6)
something like that?

In order BST traversal: find

I am trying to find the kth smallest element of binary search tree and I have problems using recursion. I understand how to print the tree inorder/postorder etc. but I fail to return the rank of the element. Can someone point where I am making a mistake? In general, I am having hard time understanding recursion in trees.
Edit: this is an exercise, so I am not looking for using built-in functions. I have another solution where I keep track of number of left and right children as I insert nodes and that code is working fine. I am wondering if it is possible to do this using inorder traversal because it seems to be a simpler solution.
class BinaryTreeNode:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
def traverseInOrder(root,order):
if root == None:
return
traverseInOrder(root.left,order+1)
print root.data,
print order
traverseInOrder(root.right,order)
"""
a
/ \
b c
/ \ / \
d e f g
/ \
h i
"""
h = BinaryTreeNode("h")
i = BinaryTreeNode("i")
d = BinaryTreeNode("d", h, i)
e = BinaryTreeNode("e")
f = BinaryTreeNode("f")
g = BinaryTreeNode("g")
b = BinaryTreeNode("b", d, e)
c = BinaryTreeNode("c", f, g)
a = BinaryTreeNode("a", b, c)
print traverseInOrder(a,0)
If this is an academic exercise, make traverseInOrder (or similar method tailored to the purpose) return the number of children it visited. From there things get simpler.
If this isn't academic, have a look at http://stromberg.dnsalias.org/~dstromberg/datastructures/ - the dictionary-like objects are all trees, and support iterators - so finding the nth is a matter of zip(tree, range(n)).
You could find the smallets element in the binary search tree first. Then from that element call a method to give you the next element k times.
For find_smallest_node method, note that you can traverse all the nodes "in-order" until reach to smallest. But that approach takes O(n) time.
However, you do not need a recursion to find the smallest node, because in BST smallest node is simply the left most node, so you can traverse the nodes until finding a node that has no left child and it takes O(log n) time:
class BST(object):
def find_smallest_node(self):
if self.root == None:
return
walking_node = self.root
smallest_node = self.root
while walking_node != None:
if walking_node.data <= smallest_node.data:
smallest_node = walking_node
if walking_node.left != None:
walking_node = walking_node.left
elif walking_node.left == None:
walking_node = None
return smallest_node
def find_k_smallest(self, k):
k_smallest_node = self.find_smallest_node()
if k_smallest_node == None:
return
else:
k_smallest_data = k_smallest_node.data
count = 1
while count < k:
k_smallest_data = self.get_next(k_smallest_data)
count += 1
return k_smallest_data
def get_next (self, key):
...
It just requires to keep the parent of the nodes when inserting them to the tree.
class Node(object):
def __init__(self, data, left=None, right=None, parent=None):
self.data = data
self.right = right
self.left = left
self.parent = parent
An implementation of the bst class with the above methods and also def get_next (self, key) function is here. The upper folder contains the test cases for it and it worked.

How to use a generator to iterate over a tree's leafs

The problem:
I have a trie and I want to return the information stored in it. Some leaves have information (set as value > 0) and some leaves do not. I would like to return only those leaves that have a value.
As in all trie's number of leaves on each node is variable, and the key to each value is actually made up of the path necessary to reach each leaf.
I am trying to use a generator to traverse the tree postorder, but I cannot get it to work. What am I doing wrong?
My module:
class Node():
'''Each leaf in the trie is a Node() class'''
def __init__(self):
self.children = {}
self.value = 0
class Trie():
'''The Trie() holds all nodes and can return a list of their values'''
def __init__(self):
self.root = Node()
def add(self, key, value):
'''Store a "value" in a position "key"'''
node = self.root
for digit in key:
number = digit
if number not in node.children:
node.children[number] = Node()
node = node.children[number]
node.value = value
def __iter__(self):
return self.postorder(self.root)
def postorder(self, node):
if node:
for child in node.children.values():
self.postorder(child)
# Do my printing / job related stuff here
if node.value > 0:
yield node.value
Example use:
>>trie = Trie()
>>trie.add('foo', 3)
>>trie.add('foobar', 5)
>>trie.add('fobaz', 23)
>>for key in trie:
>>....print key
>>
3
5
23
I know that the example given is simple and can be solved using any other data structure. However, it is important for this program to use a trie as it is very beneficial for the data access patterns.
Thanks for the help!
Note: I have omitted newlines in the code block to be able to copy-paste with greater ease.
Change
self.postorder(child)
to
for n in self.postorder(child):
yield n
seems to make it work.
P.S. It is very helpful for you to left out the blank lines for ease of cut & paste :)

Categories

Resources