"""Basic tree data structure."""
from collections import deque
[docs]class Tree():
"""Recursive tree data structure."""
def __init__(self):
"""Constructor of empty tree."""
self.parent = None
self.siblings = []
[docs] def add(self, tree):
"""Appends tree as continuation."""
tree.parent = self
self.siblings.append(tree)
return tree
[docs] def is_root(self):
"""Returns True if tree has no parent."""
return self.parent is None
[docs] def is_fork(self):
"""Returns True for a branching point (except root)."""
return len(self.siblings) > 1 and not self.is_root()
[docs] def is_leaf(self):
"""Returns True for a terminal node."""
return len(self.siblings) == 0
[docs] def preorder(self):
"""Traverses tree in pre-order (depth first).
Yields:
sequence of tree nodes (generator object).
"""
queue = deque((self,))
while queue:
node = queue.pop()
queue.extend(reversed(node.siblings))
yield node
[docs] def postorder(self):
"""Traverses tree in post-order (depth first).
Yields:
sequence of tree nodes (generator object).
"""
queue = deque((self,))
visited = set()
while queue:
node = queue[-1]
if node not in visited:
visited.add(node)
queue.extend(reversed(node.siblings))
else:
queue.pop()
yield node
[docs] def levelorder(self):
"""Traverses tree in level-order (breadth first).
Yields:
sequence of tree nodes (generator object).
"""
queue = deque((self,))
visited = set()
while queue:
node = queue[-1]
if node not in visited:
visited.add(node)
queue.extend(node.siblings)
else:
queue.pop()
yield node
[docs] def ascendorder(self):
"""Iterates tree nodes in ascending order until root is reached.
Yields:
sequence of tree nodes (generator object).
"""
node = self
while node is not None:
yield node
node = node.parent
[docs] def leaves(self):
"""Iterates tree terminals.
Returns:
sequence of tree nodes (generator object).
"""
return filter(Tree.is_leaf, self.preorder())
[docs] def forks(self, iterator=preorder):
"""Iterates tree branching points.
Args:
iterator: iterator type (defaults to ``Tree.preorder``)
Returns:
sequence of tree nodes (generator object).
"""
return filter(Tree.is_fork, iterator(self))
[docs] def degree(self):
"""Returns node degree."""
return len(self.siblings)
[docs] def size(self):
"""Returns tree size."""
return sum(1 for node in self.preorder())
[docs] def breadth(self):
"""Returns tree breadth."""
return sum(1 for node in self.leaves())
[docs] def depth(self):
"""Returns node depth."""
return sum(1 for node in self.ascendorder()) - 1
level = depth
[docs] def height(self):
"""Returns tree height."""
path = []
node_depth = self.depth()
for leaf in self.leaves():
path.append(leaf.depth() - node_depth)
return max(path)
[docs] def width(self):
"""Returns tree width."""
node_depth = self.depth()
root = deque(self.ascendorder(), maxlen=1).pop()
return sum(1 for node in root.preorder() if node.depth() == node_depth)