|
|
|
from collections import deque |
|
import collections |
|
|
|
class Node: |
|
def __init__(self, node=None): |
|
self.parent = node |
|
self.children = [] |
|
self.value = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
def linear_tree(levels): |
|
root = Node() |
|
root.value = (0,'>') |
|
|
|
stack = [root] |
|
|
|
while len(stack): |
|
node = stack.pop() |
|
|
|
level,name = node.value |
|
|
|
if level < levels: |
|
for i in range(8): |
|
child_node = Node(node) |
|
child_name = name + '.%s' % i |
|
child_node.value = (level+1, child_name) |
|
node.children += [child_node] |
|
stack.append(child_node) |
|
return root |
|
|
|
|
|
|
|
|
|
|
|
|
|
def postorder_traverse(node0, visitor): |
|
|
|
stack = [ node0 ] |
|
|
|
#///{node => completed metadata} |
|
finished_node_metadata = {} |
|
|
|
#///{node => completed child count} |
|
node_children_completed = collections.defaultdict(int) |
|
while len(stack): |
|
|
|
node = stack.pop() |
|
|
|
assert node is not None |
|
assert node.children is not None |
|
assert node not in finished_node_metadata |
|
|
|
|
|
if len(node.children) == 0: |
|
|
|
assert node not in node_children_completed |
|
|
|
metadata = visitor(node, []) |
|
finished_node_metadata[node] = metadata |
|
node_children_completed[node.parent] += 1 |
|
assert node not in node_children_completed |
|
continue |
|
|
|
|
|
assert len(node.children) > 0 |
|
|
|
#this node has not been visited before |
|
if node not in node_children_completed: |
|
|
|
node_children_completed[node] = 0 |
|
|
|
#put the node back on the stack. |
|
stack.append(node) |
|
|
|
|
|
#put the children on the stack |
|
|
|
siblings = [] |
|
for child in node.children: |
|
siblings.append(child) |
|
|
|
|
|
#put them on in reverse order; so that they are processed in order. |
|
stack += reversed(siblings) |
|
|
|
|
|
continue |
|
|
|
assert len(node.children) > 0 |
|
assert node in node_children_completed |
|
assert node_children_completed[node] == len(node.children) |
|
|
|
metadatas = [] |
|
#collect children's metadata |
|
# and also erase them from the map. |
|
for child in node.children: |
|
|
|
assert child not in node_children_completed |
|
assert child in finished_node_metadata |
|
|
|
child_metadata = finished_node_metadata[child] |
|
|
|
metadatas.append(child_metadata); |
|
finished_node_metadata.pop(child); |
|
|
|
|
|
#viit this node. |
|
metadata = visitor(node, metadatas); |
|
|
|
#remember the metadata result |
|
finished_node_metadata[node] = metadata; |
|
|
|
#let the parent know this child completed. |
|
if node.parent: |
|
node_children_completed[node.parent] += 1; |
|
|
|
#stop tracking the children's visit status. |
|
assert node in node_children_completed |
|
node_children_completed.pop(node) |
|
|
|
assert node not in node_children_completed |
|
|
|
|
|
|
|
|
|
assert node0 is not None |
|
assert node0.children is not None |
|
assert len(node_children_completed) == 0 |
|
assert len(finished_node_metadata) == 1 |
|
assert node0 in finished_node_metadata |
|
|
|
metadata = finished_node_metadata[node0]; |
|
return metadata; |
|
|
|
|
|
|
|
|
|
def print_node(node, metadatas): |
|
print (node.value) |
|
|
|
|
|
root = linear_tree(3) |
|
postorder_traverse(root, print_node) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|