Our textbook recommends a relatively simple representation using Python's tuples (this is a built-in structure that is similar to a list, but immutable). The basic format used is a triple,
(label, leftsubtree, rightsubtree)By convention, we will use a representation where if a node doesn't have any children, we will use empty tuples, such as
('C', (), ())
By this convention, a tree that might be represented graphically as
B / A \ Cwould be represented by the recursive structure
('A', ('B', (), ()), ('C', (), ()) )although to Python, the whitespace and indentation is not actually important in this context, so this could actually be viewed more streamlined as:
('A', ('B', (), ()), ('C', (), ()) )As a more complex example, the following tree
B / / E A / \ D \ / \ C F \ Gwould be represented by the recursive structure
('A', ('B',(),()), ('C', ('D', ('E',(),()), ('F',(),()) ), ('G', (), ()) ) )which is equally valid in Python as
('A', ('B',(),()), ('C', ('D', ('E',(),()), ('F',(),()) ), ('G', (), ()) ) )
While the above tree representation may quickly get unweildy for a human, it turns out that we can write algorithms that work with such a structure quite easily, by using the power of recursion to repeat processes on subtrees. We'll explore several examples of such recursive algorithms.
def nodeCount(tree): """Return the total number of nodes in the given tree.""" if tree == (): return 0 # base case represents an empty tree else: return 1 + nodeCount(tree[1]) + nodeCount(tree[2])
def height(tree): """Return the number of levels of the tree.""" if tree == (): return 0 # base case represents an empty tree else: return 1 + max(height(tree[1]), height(tree[2]))
def leafList(tree): """Return list of labels for the leaves of the tree.""" root,left,right = tree # unpack the tuple if left == right == (): return [ root ] # tree with one node else: return leafList(tree[1]) + leafList(tree[2])