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
\
G
would 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])