I did recursive procedure for binary tree post order traversal in python. This is the code.
from collections import namedtuple
from sys import stdout
Node = namedtuple('Node', 'data, left, right')
tree = Node(1,
Node(2,
Node(4,
Node(7, None, None),
None),
Node(5, None, None)),
Node(3,
Node(6,
Node(8, None, None),
Node(9, None, None)),
None))
def printwithspace(i):
stdout.write("%i " % i)
def postorder(node, visitor = printwithspace):
if node:
print "%d-->L"%node.data
postorder(node.left, visitor)
print "%d-->R"%node.data
postorder(node.right, visitor)
print "Root--%d"%node.data
else:
print "Null"
stdout.write('\n postorder: ')
postorder(tree)
stdout.write('\n')
Now, I want to do an iterative procedure for binary tree post order traversal in PYTHON. Can anyone help with this?
Thanks in advance.
The following code should work. Basically, you do a depth first search with a stack for the nodes.
Additionally, you have a second stack which parallelly stores whether a node has been expanded already.
def postorder_iteratively(node):
stack = [node]
expanded = [False]
while stack:
while stack and not stack[-1]: #remove "non-existent" nodes from the top
stack = stack[:-1]
expanded = expanded[:-1]
if stack and not expanded[-1]: #expand node
stack += [stack[-1].right, stack[-1].left]
expanded[-1] = True
expanded += [False, False]
elif stack and expanded[-1]: #if node has been expanded already, print it
print stack[-1].data
stack = stack[:-1]
expanded = expanded[:-1]
Here is the code
def postorder_traverse(root):
result = []
list = [] #simply use list to mimic stack
visited_node = None
cur_node = root
while len(list) > 0 or cur_node is not None:
if cur_node is not None:
#remember the middle node by "pushing" it to the stack
list.append(cur_node)
cur_node = cur_node.left
else:
middle_node = list[len(list)-1]
#visit the middle node only if the right node is none
#or the right node is already visited
if middle_node.right is None or visited_node == middle_node.right:
#visit the middle node
result.append(middle_node.data)
visited_node = list.pop(len(list)-1)
else:
#else, move to right
cur_node = middle_node.right
return result
Related
I'm currently working on leetcode problem 366 where we have to find list of lists that contains values of leaves of each generation. I wanted to achieve this by recursion where if a node does not have left or right child, the value is recorded then the node removed by setting it to None. Here is my code:
def findLeaves(self, root: Optional[TreeNode]) -> List[List[int]]:
leaf_list = []
sub_list = []
def traverse(node):
if node == None:
return
if node.left == None and node.right == None:
sub_list.append(node.val)
node = None
return
traverse(node.left)
traverse(node.right)
return root
while True:
if root == None:
break
sub_list = []
traverse(root)
leaf_list.append(sub_list)
print(leaf_list)
return leaf_list
The problem seems to be that when a certain node is set to None, that change isn't retained. Why is it that I can't set a node to None to remove it?
Thanks
The tree can only be mutated when you assign to one if its node's attributes. An assignment to a variable, only changes what the variable represents. Such assignment never impacts whatever previous value that variable had. Assigning to a variable is like switching from one value to another without affecting any data structure. So you need to adapt your code such that the assignment of None is done to a left or right attribute.
The exception is for the root node itself. When the root is a leaf, then there is no parent to mutate. You will then just discard the tree and switch to an empty one (None).
One way to achieve this, is to use the return value of traverse to update the child-reference (left or right) that the caller of traverse needs to update.
Here is your code with those adaptations:
def findLeaves(root):
sub_list = []
def traverse(node):
if not node:
return
if not node.left and not node.right:
sub_list.append(node.val)
return # By returning None, the parent can remove it
node.left = traverse(node.left) # Assign the returned node reference
node.right = traverse(node.right)
return node # Return the node (parent does not need to remove it)
leaf_list = []
while root:
sub_list = []
root = traverse(root)
leaf_list.append(sub_list)
return leaf_list
A lot of people say loop and recursion is basically the same. The only difference between two is that some algorithms are easier to understand in recursion or iteration. Besides, loop is always preferred, because of overhead of function calls. However, here is a python code to get the height of a binary search tree . How can I write it using loop?
bst = [(1, 2), (3, None), (None, None), (None, None)]
def recursion_height(tree, v=0):
if v is None:
return -1
else:
return max(recursion_height(tree, tree[v][0]), recursion_height(tree, tree[v][1])) + 1
This can be implemented iteratively using queues.
# A binary tree node
class Node:
# Constructor to create new node
def __init__(self, data):
self.data = data
self.left = None
self.right = None
# Iterative method to find height of Binary Tree
def treeHeight(root):
# Base Case
if root is None:
return 0
# Create a empty queue for level order traversal
q = []
# Enqueue Root and Initialize Height
q.append(root)
height = 0
while(True):
# nodeCount(queue size) indicates number of nodes
# at current level
nodeCount = len(q)
if nodeCount == 0 :
return height
height += 1
# Dequeue all nodes of current level and Enqueue
# all nodes of next level
while(nodeCount > 0):
node = q[0]
q.pop(0)
if node.left is not None:
q.append(node.left)
if node.right is not None:
q.append(node.right)
nodeCount -= 1
# Driver program to test above function
# Let us create binary tree shown in above diagram
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
print "Height of tree is", treeHeight(root)
It seems obvious that a recursion is realized using stacks. But how indeed a general recursion realized using a stack? For example, if we have a custom function that is recursive, can we rewrite the code using just a stack and iteration?
Here is one example (I was giving the wrong example in another post):
def recursiveCall(node):
if node==None:
return (0,True)
(left,lstatus) = recursiveCall(node.left)
(right,rstatus) = recursiveCall(node.right)
if lstatus==True and rstatus==True:
if abs(left-right)<=1:
return (max(left,right)+1,True)
else:
return (0,False)
else:
return (0,False)
or an easier one :
def recursiveInorder(node):
if node==None:
return
recursiveInorder(node.left)
print(node.val)
recursiveInorder(node.right)
how do you realize this recursion using stacks? Note, I am not asking for an iteration solution to the above two examples. I believe there must be. But I suppose those iteration solutions are not trying to reproduce the recursion mechanism using a stack. What I wanted is to see, if ever possible, those recursions can be completely replaced by custom coded stack-mechanism (basically making the implicit recursion mechanism embedded in the compiler or whatsoever explicit) .
I think one needs to find a way to track and restore program status, local variables etc?
thx.
node class is defined as:
class node:
def __init__(self,x):
self.val=x
self.left=None
self.right=None
Basically, when simulating a recursive call, you need to push on the stack local variables and the point where execution should resume after returning.
I'll indicate the relevant points of execution by numbered comments here. Think of them as goto labels.
def recursiveInorder(node):
#0
if node==None:
return
recursiveInorder(node.left)
#1
print(node.val)
recursiveInorder(node.right)
#2
return
Now, we can use an if-elif statement to simulate goto statements:
def in_order(node):
stack = [(None, None)] #sentinel
goto = 0
while stack:
if goto == 0:
if node is None:
#return
(node, goto) = stack.pop()
else:
#push state and recurse left
stack.append((node, goto+1))
(node, goto) = (node.left, 0)
elif goto == 1:
print(node.val)
#push state and recurse right
stack.append((node, goto+1))
(node, goto) = (node.right, 0)
else:
#return
(node, goto) = stack.pop()
In the end, (None, None) will be popped but the values are never used because the while loop ends.
The above code is the result of a straightforward conversion. Next, we can apply various optimizations to simplify it.
The last else branch is not doing useful work. We can remove it if we also remove the push that would take us there.
def in_order(node):
stack = [(None, None)] #sentinel
goto = 0
while stack:
if goto == 0:
if node is None:
#return
(node, goto) = stack.pop()
else:
#push state and recurse left
stack.append((node, goto+1))
(node, goto) = (node.left, 0)
else:
print(node.val)
#recurse right
(node, goto) = (node.right, 0)
Now the goto value that is pushed the stack is always 1. We only need to push node on the stack and assign goto = 1 when popping from stack.
def in_order(node):
stack = [None] #sentinel
goto = 0
while stack:
if goto == 0:
if node is None:
#return
(node, goto) = (stack.pop(), 1)
else:
#push state and recurse left
stack.append(node)
(node, goto) = (node.left, 0)
else:
print(node.val)
#recurse right
(node, goto) = (node.right, 0)
If we change the inner if into a while loop...
def in_order(node):
stack = [None] #sentinel
goto = 0
while stack:
if goto == 0:
while node is not None:
#push state and recurse left
stack.append(node)
node = node.left
#return
(node, goto) = (stack.pop(), 1)
else:
print(node.val)
#recurse right
(node, goto) = (node.right, 0)
...we see that after each branch of the if statement, we want to go to the other branch, until in the end we pop the sentinel value. We can eliminate goto and the if statement, if we add a check for empty stack in the middle. If we place the check before the pop, we don't need the sentinel on stack any more.
def in_order(node):
stack = []
while True:
while node is not None:
stack.append(node)
node = node.left
if stack:
node = stack.pop()
print(node.val)
node = node.right
else:
return
Now the code looks clean and simple.
So far I have
def tree_iterate():
parent, current = None, self.root
lst = []
while current is not None:
if current.left not None:
lst.append(current.item)
parent, current = current, current.left
if current.right not None:
lst.append(current.item)
parent, current = current, current.right
(sorry about spacing I'm quite new at this)
I'm not quite sure how to iterate on both sides of the tree when current has left and right, without using recursion. My main goal is to have a list of all the nodes in this BSTenter code here
To get a list of all nodes in the BST iteratively, use Breadth-First Search (BFS). Note that this won't give you the nodes in sorted order:
queue = [root]
result = []
while queue:
l = queue.pop(0)
result.append(l)
if l.left != None:
queue.append(l.left)
if l.right!= None:
queue.append(l.right)
If you want the nodes in sorted order, you will need to simulate inorder traversal using a stack:
result = []
stack = [root]
while stack:
stack[-1].visited = True
if stack[-1].left != None and not stack[-1].left.visited:
stack.append(stack[-1].left)
else:
node = stack.pop()
result.append(node)
if stack[-1].right != None:
stack.append(stack[-1].right)
I am trying to write a simple method to link the nodes of a tree together in this way:
Every leaf is linked to the previous and the next leaf in the tree
Every non-leaf is linked to the previous and the next leaf in the tree
For example, if we have this tree:
A
/ | \
B C D
/ \ / \
E F G H
|
I
This should be the result of the method:
B.nextToken = E
C.prevToken = B
E.nextToken = F
E.prevToken = B
F.nextToken = I
C.nextToken = I
H.prevToken = I
Here is the method code:
prevToken = None
def depthFirstTraverseTokenLinking(tree):
global prevToken
if len(tree.children) == 0:
tree.prevToken = prevToken
if prevToken != None :
prevToken.nextToken = tree # Is something wrong with this line?
prevToken = tree
return
for c in tree.children:
depthFirstTraverseTokenLinking(c)
tree.prevToken = tree.children[0].prevToken
tree.nextToken = tree.children[-1].nextToken
For some strange reason, the non-leaves aren't linked to the next leaves, for example:
C.nextToken = None
Although
F.nextToken = I
I wonder why is that happening? The last lines at the end of the recursive function should grantee that a parent will have the same next as its last child!
The problem is, when you visit C, you traverse only it's children E & F.
"I" hasn't been visited yet, so C.children[-1].nextToken == None because only visiting "I" will set F.nextToken
Solution: you'll have to do a run on all leaves first, then a second run on the internal nodes.
For example:
prevToken = None
def depthFirstTraverseTokenLinking(tree):
depthFirstTraverseTokenLinkingPhase1(tree)
depthFirstTraverseTokenLinkingPhase2(tree)
def depthFirstTraverseTokenLinkingPhase1(tree):
global prevToken
if len(tree.children) == 0:
tree.prevToken = prevToken
if prevToken != None :
prevToken.nextToken = tree # Is something wrong with this line?
prevToken = tree
return
for c in tree.children:
depthFirstTraverseTokenLinkingPhase1(c)
def depthFirstTraverseTokenLinkingPhase2(tree):
if len(tree.children) == 0:
return
for c in tree.children:
depthFirstTraverseTokenLinkingPhase2(c)
if tree.children[0].prevToken is not None:
tree.prevToken = tree.children[0].prevToken
else:
tree.prevToken = tree.children[0]
if tree.children[-1].nextToken is not None:
tree.nextToken = tree.children[-1].nextToken
else:
tree.nextToken = tree.children[-1]
Also note the change for the prevToken/nextToken of internal nodes. This is needed if you want them to link to the actual first/last leaf.
Alternatively, use generators an an instance-checking loop
The generator yields the node as the base case if the node has no children, else another generator to travel down the tree. Caveat here is that node.children is ordered from left to right.
def leafs(node):
if len(node.children) == 0:
yield node
else:
for child in node.children:
yield leafs(child)
...and a loop with stack of generators... This got uglier as I wrote it - I think you could clean it up a bit and get rid of the while True...
current_node = leafs(a)
stack = []
last_node = None
while True:
if isinstance(current_node, types.GeneratorType):
stack.append(current_node)
current_node = current_node.next()
else:
if last_node and last_node != current_node:
last_node.nextToken = current_node
current_node.prevToken = last_node
last_node = current_node
try:
current_node = stack[-1].next()
except StopIteration:
stack.pop()
except IndexError:
break