Download as pdf or txt
Download as pdf or txt
You are on page 1of 17

C

H
A
P Trees
T
E
R

11 11.1 Introduction to trees


In this chapter, we study the particular type of graph known as a tree, and
investigate some applications of trees to practical problems. Trees arise in
the problem of designing a communications network as cheaply as
possible, and in the representation of hierarchical structures and decision
processes, as well as in many other situations.
As we did in Chapter 10, we assume that all of the graphs we are
dealing with are finite.
We begin with a definition.

Definition A cycle is a path in a graph with the following properties:


It includes at least one edge.
▼ ▼ ▼

There are no repeated edges.


The first and last vertices coincide, but there are no other repeated
vertices.
A cycle with n edges is called an n-cycle.

A cycle is thus a circuit with some additional properties. A vertex by itself


is not a cycle, because a cycle must include at least one edge. If two cycles
consist of the same vertices and edges, we regard them as the same cycle;
for example, a cycle with edges e1e2e3e4 is the same cycle as e2e3e4e1 and
e3e2e1e4. Note that when we write down a cycle, we do not need to state a
starting vertex.
A 1-cycle is a loop, while a 2-cycle is formed by a pair of parallel edges.
The shortest possible cycle in a simple graph is a 3-cycle.

Example 11.1.1 List the cycles in the graph shown in Figure 11.1.

200
Trees

Figure 11.1

Solution There are three cycles: abc, cegd and abegd.

Definition A tree is a connected graph with no cycles.

Some examples of trees are shown in Figure 11.2.

Figure 11.2

If the word ‘connected’ is removed from the definition of a tree, we are


left with a definition for a graph that has no cycles but need not be
connected. Such a graph is called a forest; a forest consists of one or more
components, each of which is a tree.
Three basic properties of trees are listed below. You should have no
difficulty convincing yourself that they are true.
For each pair of vertices u and v in a tree, there is exactly one path

from u to v that does not repeat any vertices or edges.


Inserting an edge between any two vertices of a tree produces a graph

containing a cycle.
Removing any edge from a tree produces a disconnected graph.

The property given in the following theorem is a bit more subtle.

Theorem Any tree with n vertices has n – 1 edges.

It is easily checked that the theorem is true for each of the trees shown in
Figure 11.2. For example, the rightmost tree has 13 vertices and 12 edges.
We will prove the theorem using induction on n. The proof is an
interesting example of induction because it shows that the method can be
applied more widely than just to the algebraic problems we dealt with in
Chapter 7.

201
Discrete mathematics for computing

In the course of the proof, we will need to use the following fact, which
should be obvious: in any tree with at least two vertices, it is always
possible to find a vertex with degree 1.
For the base step of the proof, we simply note that a tree with one
vertex must have no edges, because a tree cannot contain loops.
We begin the inductive step by assuming that any tree with k vertices
has k – 1 edges. Let T be a tree with k + 1 vertices. ‘Prune’ the tree T by
removing a vertex v with degree 1 and the edge e incident to v. The
resulting graph is a tree with k vertices, and by the inductive hypothesis it
has k – 1 edges. Now restore T by replacing v and e. In the process, the
number of edges increases by 1, so T has k edges. This completes the
inductive step.
It follows by induction that a tree with n vertices has n – 1 edges, for all
values of n. This concludes the proof.
We will use this result in the minimal spanning tree algorithm in the
next section.

11.2 Local area networks and minimal spanning trees


In this section, we will solve a practical problem in the design of local area
networks.
Suppose there is a site, such as a university campus, on which there are
several buildings containing computer laboratories. We would like to
build a communications network, called a local area network (or LAN), in
such a way that it is possible for a computer in any laboratory to
communicate with a computer in any other laboratory. Of course, this
does not mean that every pair of buildings must be directly linked; it is
quite acceptable for two buildings to be linked indirectly via a third, for
example. Given that installing a link between two buildings is a costly
process, we would like to build the network as cheaply as possible.
For example, suppose we have four buildings: A, B, C and D. The costs
of linking each pair of buildings (in thousands of dollars) are tabulated in
Table 11.1.

Table 11.1
A B C D
A –
B 120 –
C 100 105 –
D 140 125 90 –

We can represent the situation by means of a graph in which the


vertices are the buildings (Figure 11.3). A graph of this type is called a
weighted graph.

202
Trees

Figure 11.3

Definitions A weighted graph is a simple graph in which each edge has a positive
number attached to it. The number attached to an edge in a weighted
graph is called the weight of the edge.

In the present example, the weights are the costs of installing the links. In
other problems in which weighted graphs are used, the weights might
represent road distances, signal travelling times, or link capacities.
We do not need to install all of the links in our example; it is sufficient
to install just the three cheapest: CD, BC and AC. With these links in
place, any two laboratories can communicate with one another.
This example was small enough that the solution could be obtained
easily by inspection. In a problem involving a large number of sites, it is
not practical to determine the solution by trial and error in this way. For
this reason, we now turn our attention to developing an algorithm for
finding the cheapest network linking the sites.
As a first step towards solving the problem, we can look for some
properties that the solution must have. The solution is itself a graph,
consisting of all of the vertices but only some of the edges of the original
weighted graph. Clearly the solution must be a connected graph, in order to
ensure that any two sites can communicate with each other. Furthermore,
since the solution represents the cheapest possible network connecting the
sites, it cannot contain any cycles because if a cycle were present, then one
of the edges in the cycle could be removed to produce a connected graph
with a smaller total weight.
We can sum up these observations as follows. The solution to the
problem must be a tree. The vertices of the tree must be the vertices of the
original graph, and the edges of the tree must be selected from the set of
edges in the original graph. A tree that satisfies these requirements is
called a spanning tree of the graph.
Typically, a connected graph has many spanning trees. In Figure 11.3,
not only do the edges CD, BC and AC form a spanning tree, but so do the
edges AB, AC and AD, and the edges AB, BC and CD. The problem is to
find a spanning tree with the smallest possible total weight, since this will
represent the cheapest possible network. A spanning tree with this
property is called a minimal spanning tree.
Here, then, is the problem stated in the terminology of graph theory.

Minimal Spanning Tree Problem


Design an algorithm that inputs a connected weighted graph and outputs
a minimal spanning tree for the graph.

203
Discrete mathematics for computing

How might we go about finding a minimal spanning tree? A plausible


approach would be to start at one of the vertices, and pick an edge with
the least weight of all the edges incident to that vertex. This edge forms
the start of our minimal spanning tree. Next, we could look for an edge
with least weight of all the edges that join up with the edge we already
have. Continuing in this way, adding one edge at a time, we might hope to
obtain a minimal spanning tree.
We would have to make one modification to this procedure. If the
addition of an edge would create a cycle, then clearly we would not want
to add that edge. What we need to do at each step, then, is to add an edge
of least weight that does not form a cycle.
The procedure we have just described can be formulated as an
algorithm, known as Prim’s algorithm:
1. Input a connected weighted graph G, with vertex set V(G) = {v1, ..., vn}
and edge set E(G) = {e1, ..., em}
2. T ! { v1 }; unused _ edges ! E(G)
3. For i = 1 to n – 1 do
3.1. e ! the first edge with minimal weight in unused_edges that is
incident to exactly one vertex in T
3.2. v ! the vertex not in T to which e is incident
3.3. T ! T "{e, v}
3.4. unused _ edges ! unused _ edges #{e}
4. Output T
Notice that the For-do loop is executed n – 1 times (where n is the
number of vertices in the weighted graph), because any tree with n
vertices has n – 1 edges, and a spanning tree for a graph has the same
number of vertices as the original graph.

Example 11.2.1 Use Prim’s algorithm to find a minimal spanning tree for the weighted
graph shown in Figure 11.4.

Figure 11.4

Solution Starting at vertex A, we find that the edge with least weight incident to A
is the edge AD with weight 20, so this is the first edge in the minimal
spanning tree T.
We look next at the edges incident to both A and D and not yet in T. Of
these, DE has the least weight, so we add it to T.

204
Trees

In a similar fashion, we add EB and EC to T. At this stage, the edge with


least weight incident to a vertex of T is BC with weight 10, but this edge is
incident to two vertices of T, and therefore we cannot add it to T. The
edge with least weight that is incident to exactly one vertex of T is BF, so
this is the edge to be added.
The tree T now has a total of 5 edges. Since the original graph has 6
vertices, and 5 = 6 – 1, there are no more edges to be added.
The minimal spanning tree is shown in Figure 11.5; it has a total weight
of 58.

Figure 11.5

A trace table for the algorithm is shown in Table 11.2.

Table 11.2
Step e v T unused_edges Output
2 – – {A} {AB, AD, AF, BC, BE, –
BF, CD, CE, DE, EF}
3.1–3.4 AD D {A, AD, D} {AB, AF, BC, BE, BF, –
CD, CE, DE, EF}
3.1–3.4 DE E {A, AD, D, DE, {AB, AF, BC, BE, BF, –
E} CD, CE, EF}
3.1–3.4 BE B {A, AD, D, DE, {AB, AF, BC, BF, CD, –
E, BE, B} CE, EF}
3.1–3.4 CE C {A, AD, D, DE, {AB, AF, BC, BF, CD, –
E, BE, B, CE, C} EF}
3.1–3.4 BF F {A, AD, D, DE, {AB, AF, BC, CD, EF} –
E, BE, B, CE, C,
BF, F}
4 BF F {A, AD, D, DE, {AB, AF, BC, CD, EF} {A, AD, D, DE,
E, BE, B, CE, C, E, BE, B, CE, C,
BF, F} BF, F}

While Prim’s algorithm appears to be a reasonable way of finding a


spanning tree with small total weight, it is not obvious that it always

205
Discrete mathematics for computing

produces a minimal spanning tree. In fact, Prim’s algorithm does always


yield a minimal spanning tree in any connected weighted graph; the proof
of this fact is not given here, but it can be found in many textbooks on
graph theory.
Prim’s algorithm is one of a class of algorithms known as greedy
algorithms. A greedy algorithm is an algorithm in which at each step we
perform whatever action appears to be best at that step, without
considering whether it leads to the best result overall. In each iteration of
the For-do in Prim’s algorithm, we choose the lowest weight edge to add
to the tree (subject to the restriction that no cycles are created). It turns
out that this process leads to the lowest total weight in the spanning tree.
An example of a problem in which a greedy strategy doesn’t always
work is the Travelling sales representative (or Travelling salesman)
problem. A sales representative wants to visit a number of towns and
return home, travelling the shortest possible total distance in the process.
If we represent the towns and roads by a weighted graph, in which the
weights are the road distances, then the problem becomes: find the circuit
with the smallest possible total weight passing through all of the vertices.
(We could call this a minimal spanning circuit, as distinct from the
minimal spanning tree of the previous problem.)
A greedy approach to the Travelling sales representative problem
might work in the following way. Starting from the home vertex, travel at
each step by the shortest available path to the nearest vertex that has not
been visited already. When all of the vertices have been visited, return to
the starting vertex by the shortest path. This method is known as the
‘Nearest neighbour algorithm’.
If the Nearest neighbour algorithm is applied to the graph in Example
11.2.1 (with the weights now interpreted as distances, and with A as the
home vertex), the result is the circuit ADEBCBFA, with a total distance of
95. This is not the best solution, however; for example, the circuit
ADCEBFA is shorter, with a total distance of 88. Greed doesn’t always pay!
We mention in passing that it is not known whether it is possible to
design an efficient algorithm for the Travelling sales representative
problem, where ‘efficient’ is used in a sense that we will make precise in
Chapter 13.
There is one further question that we would like to answer before we
conclude this section. How can a weighted graph be represented in a form
suitable for machine computation? The answer that most readily comes to
mind is to use a matrix similar to an adjacency matrix, but to put the
weight of the edge from vertex vi to vertex vj, rather than the number of
edges, in row i and column j. (Recall that, by definition, every weighted
graph is a simple graph, so there will be no multiple edges.) A matrix of
this type is called a weight matrix.
What should we put in row i and column j if there is no edge from vi to
vj? In order to answer this question, we need to realise that there are two
types of weighted graphs. In the first type, the weights represent a penalty
of some kind, such as a distance or a cost, which we would want to try to
minimise in a typical application. The graphs in the Minimal spanning

206
Trees

tree problem and the Travelling sales representative problem are of this
type. In the second type, the weights represent something we would want
to maximise, such as the capacity of a communications channel. In a
graph of the first type, a pair of vertices with no connecting edge is even
‘worse’ than a pair joined by an edge with a very large weight. This is
indicated in the weight matrix by treating two non-adjacent vertices as if
they were joined by an edge of infinite weight. For weighted graphs of the
second type, a weight of zero is appropriate for non-adjacent vertices. The
entries on the diagonal of the weight matrix are zero for both types of
weighted graph. We consider only the first type here.

Definition Let G be a weighted graph with vertices v1, v2, ..., vn, in which the weights
represent a penalty of some kind. The weight matrix of G is the n × n
matrix for which the entry wij in the ith row and the jth column is given
by the rule:
Ï0 if i = j
ÔÔ
wij = Ìthe weight of the edge from i to j if vi and v j are adjacent
Ô
ÔÓ• if i π j and vi and v j are not adjacent

Example 11.2.2 Write down the weight matrix for the weighted graph in Example 11.2.1.

Solution A B C D E F
A %0 22 $ 20 $ 25 (
B ' 22 0 10 $ 5 12 *
' *
C '$ 10 0 18 8 $ *
D ' 20 $ 18 0 13 $ *
' *
E '$ 5 8 13 0 15 *
F '
& 25 12 $ $ 15 0 *)

11.3 Minimal distance paths


Suppose we have a weighted graph that represents a communications
network as in the previous section, but now the weight of each edge
represents the time taken by a signal to travel along that link in the
network. Given any two nodes (vertices) in the network, it is a problem of
considerable practical importance to find the quickest path for a signal to
take through the network from one node to the other.

207
Discrete mathematics for computing

In order to cast the problem in graph-theoretic terms, the following


definitions are useful.

Definitions Let G be a connected weighted graph, and let u and v be vertices in G. If P


is a path from u to v, then the length of P is the sum of the weights of the
edges in P. The distance from u to v is the smallest of the lengths of all the
paths from u to v.

We will use the notation d(u, v) to denote the distance from u to v. It will
also be convenient to use the notation weight(e) to denote the weight of
an edge e.
Notice that the definition of the length of a path in a weighted graph is
different from the definition in a graph without weights, which we
encountered in Chapter 10. (Recall that in the latter case the length of a
path is simply the number of edges in the path.)
In the application we have in mind, the weights actually represent
times rather than distances. However, we can imagine that a weighted
graph could also represent a road network in which the weights are the
road distances.
The problem can now be stated in the terminology of graph theory as
follows.

Minimum distance problem


Design an algorithm to input a connected weighted graph and two
vertices u and v, and output the distance d(u, v) from u to v together with
a path from u to v that achieves this distance.
It turns out that it is no more difficult to design an algorithm to answer a
slightly more general problem: given a weighted graph G and a vertex u,
find the distances from u to all vertices v of G. Roughly speaking, the
reason for this is that in the process of finding the distance from u to v,
we also find the distance from u to each vertex along the way.
Dijkstra’s algorithm is an algorithm that provides an efficient solution
to the minimum distance problem. Just as we did with Prim’s algorithm
for finding a minimal spanning tree, we will present Dijkstra’s algorithm
in a form suited to hand computation.
1. Input a connected weighted graph G with vertex set V(G) = {v1, ..., vn}
and edge set E(G) = {e1, ..., em}
{We will obtain, in the form of a spanning tree, T, the minimum
distance paths from v1 to each of the other vertices. In the process, we
will also obtain the distance of each vertex from v1 as we add the vertex
to T.}
2. T ! { v1 }; d (v1 , v1 ) ! 0
3. For j = 1 to n – 1 do

208
Trees

3.1. w ! the first vertex for which d(v1, w) + weight(e) is minimised,


where w ranges over all the vertices in T, and e ranges over all the
edges in G – T that are incident to w
3.2. e ! the first edge incident to w for which d(v1, w) + weight(e) is
minimised
3.3. v ! the vertex in G – T to which e is incident
3.4. T ! T "{e, v}
3.5. d (v1 , v) ! d (v1 , w) + weight (e)
4. Output T

Example 11.3.1 Apply Dijkstra’s algorithm to find the minimum distance from A to C in
the weighted graph in Example 11.2.1, and the path that achieves this
distance.

Solution Table 11.3 is a partial trace table for the algorithm.

Table 11.3
Step w e v T d(v1, v) Output
2 – – – {A} – –
3.1–3.5 A AD D {A, AD, D} 20 –
3.1–3.5 A AB B {A, AD, D, AB, B} 22 –
3.1–3.5 A AF F {A, AD, D, AB, B, 25 –
AF, F}
3.1–3.5 B BE E {A, AD, D, AB, B, 27 –
AF, F, BE, E}
3.1–3.5 B BC C {A, AD, D, AB, B, 32 –
AF, F, BE, E, BC, C}
4 B BC C {A, AD, D, AB, B, 32 {A, AD, D, AB, B, AF, F,
AF, F, BE, E, BC, C} BE, E, BC, C}

The distance from A to C is 32, and the path is ABC.

11.4 Rooted trees


In this section, we consider the kind of tree known as a rooted tree, and
investigate one of its applications to a problem in computing.
A rooted tree is a tree in which one of the vertices is specified as the
root. By convention, rooted trees are usually drawn with the root at the
top. The vertices adjacent to the root (the ‘first generation’) are shown in
a horizontal line below the root, the vertices that can be reached from the

209
Discrete mathematics for computing

root by a path of length 2 (the ‘second generation’) are shown in a line


below the first generation, and so on.
An example of a rooted tree is shown in Figure 11.6.

Figure 11.6

A family tree, showing the descendants of an individual, is a familiar


everyday example of a rooted tree. For this reason, much of the
terminology associated with family trees is carried over to rooted trees.
For example, we refer to the vertex immediately above a given vertex as
the parent of the given vertex, while a vertex immediately below a given
vertex is a child of that vertex. Note that every vertex in a rooted tree
except the root has exactly one parent. Similarly, we can say that one
vertex in a rooted tree is an ancestor or a descendant of another, with the
obvious meaning in each case. Changing the analogy, a vertex with no
children is called a leaf.
The tree diagrams we encountered in Chapter 9 are rooted trees,
although we drew them with the root on the left rather than at the top. In
that chapter, tree diagrams were used to represent decision processes, in
which we were faced with a choice at each of several steps in a procedure.
This is one of the most widely used applications of rooted trees in
computing.
As an example of a decision tree, suppose we want to sort three distinct
numbers, denoted by a, b and c, into increasing order. In order to carry
out the sorting process, we need to take the numbers two at a time and
compare them. In some cases, two such comparisons will be sufficient to
determine the order in which the three numbers should be arranged,
while in other cases three comparisons will be needed. The procedure is
depicted in the rooted tree shown in Figure 11.7. The leaves represent the
final arrangements of the three numbers into increasing order, and the
other vertices represent points at which a decision is made. The decision
process begins at the root, and moves down the tree until a leaf is
reached.

Figure 11.7

210
Trees

The rooted tree in this example has the property that every vertex that
is not a leaf has exactly two children. A rooted tree with this property is
called a binary rooted tree. In a binary rooted tree, the two children of
each parent are identified as the left child and the right child, according to
where they are placed when the tree is drawn. For any given parent
vertex, the left child is the root of the left subtree, the binary rooted tree
consisting of the left child and its descendants. Similarly, the right child is
the root of the right subtree.
There is also a recursive definition of a binary rooted tree:
1. A single vertex is a binary rooted tree.
2. If T is a binary rooted tree, and v is a leaf of T, then T "{ v1 , e 1 , v 2 , e 2 }
is a binary rooted tree, where v1 and v2 are vertices not in T, e1 is an
edge from v to v1, and e2 is an edge from v to v2.
We now show how a binary rooted tree can be used to represent the
way in which an algebraic expression is evaluated.
Suppose we have an algebraic expression containing a number of
variables and the binary operations of addition (+), subtraction (–),
multiplication (×) and division (/). An example of such an expression is
shown below:
(a – (b/c)) × (d + e)
For the sake of clarity, we have used brackets explicitly to indicate the
order in which the operations are to be carried out, including those
around b/c where brackets are not strictly necessary because of the
convention in algebra about precedence of operators.
We now imagine that this expression is being evaluated by a computer
with particular values substituted for the variables. The principal
operation in this example is the multiplication, because this is the
operation that would be executed last, after (a – (b/c)) and (d + e) have
both been evaluated. (This is exactly analogous to the principal
connective of a logical expression, which we met in Chapter 4.) The
principal operations of the subexpressions (a – (b/c)) and (d + e) are the
subtraction and the addition respectively. In turn, (a – (b/c)) contains the
subexpression (b/c) with division as its principal operation.
The structure of the expression can be depicted using a binary rooted
tree known as an expression tree (Figure 11.8).

Figure 11.8

The root of the tree is labelled with the principal operation. The left
subexpression (a – (b/c)) is represented by the left subtree, whose root is
the left child of the root of the expression tree. Similarly, the right

211
Discrete mathematics for computing

subexpression (d + e) is represented by the right subtree, whose root is the


right child of the root of the expression tree. The left subtree contains a
right subtree of its own, corresponding to the subexpression (b/c).
The way in which a computer processes the expression corresponds to
visiting the vertices of the expression tree in a particular order. A
procedure for visiting all of the vertices of a binary rooted tree in a given
order is called a traversal of the tree. We will see how different ways of
traversing an expression tree correspond to different ways of writing the
expression.
The usual way of writing an algebraic expression is to place each
operator (the symbol +, –, × or /) between the two expressions on which
it operates: 3 + 2, for example. This notation is called infix notation. Infix
notation corresponds to a method of traversing the expression tree
known as an in-order traversal.
The idea underlying in-order traversal is to visit all of the vertices
corresponding to the left subexpression, then to visit the root, and lastly
to visit the vertices corresponding to the right subexpression. The order
in which the vertices are visited within each subexpression is itself an in-
order traversal.
Here is an algorithm for carrying out an in-order traversal on a binary
rooted tree T:
Algorithm in-order_traverse(T):
1. If T is not a leaf then
1.1. in-order_traverse(left subtree of T)
2. Output the root of T
3. If T is not a leaf then
3.1. in-order_traverse(right subtree of T)
Notice that Algorithm in-order_traverse contains calls to itself in Steps 1
and 3. This makes in-order_traverse a recursive algorithm.
Suppose we wish to apply the in-order_traverse algorithm to the
expression tree in Figure 11.8. Here is a detailed description of what
happens.
In Step 1, we are required to perform an in-order traversal of the left
subtree with its root at the minus sign. To do this, we need to put
execution of this first copy of the algorithm on hold while we begin
executing a second copy with T equal to the left subtree. In Step 1 of this
second copy, we need to go on hold again and begin execution of a third
copy with T equal to the subtree with its root at a. This subtree is a leaf, so
the third copy of the algorithm executes to completion and outputs a.
Returning now to the second copy, we execute Step 2 (output –) and
move to Step 3. A third copy of the algorithm is needed again, this time
with T equal to the subtree with its root at the division sign. Now a fourth
copy is needed with T equal to the subtree with its root at b. This
produces an output of b and returns to the third copy. The third copy
continues execution and outputs /. Another fourth copy, this time using c
as the root, produces an output of c. Execution of the second copy is now
complete.

212
Trees

Step 2 of the first copy now executes, giving an output of ×.


We now move to Step 3 of the first copy. This requires us to perform an
in-order traversal of the subtree with root at the plus sign. Calling up a
second copy of the algorithm again, followed by a third copy, we output d,
then return to the second copy to output +, then call up another third
copy to output e. This completes the entire algorithm.
The output of the algorithm is the original expression with the
variables and operators in the order written (but without the brackets).
All of this sounds much more complicated than it really is. Describing
each step in detail requires a lot of words, but the process is actually fairly
straightforward.
Two other traversal methods are pre-order and post-order traversal. The
idea underlying pre-order traversal is to visit the root before visiting each
subtree. A recursive algorithm for pre-order traversal is given below:
Algorithm pre-order_traverse(T):
1. Output the root of T
2. If T is not a leaf then
2.1. pre-order_traverse(left subtree of T)
2.2. pre-order_traverse(right subtree of T)

Example 11.4.1 Carry out a pre-order traversal on the expression tree in Figure 11.8.

Solution Output the root: ×.


Pre-order traverse the left subtree. To do this, output its root (–), then
pre-order traverse its left subtree (output: a), then pre-order traverse its
right subtree (output: / b c).
Pre-order traverse the right subtree, giving an output of + d e.
The overall output is:
×–a/bc+de

An expression written in the form given by the output of a pre-order


traversal is said to be written in Polish prefix notation. In Polish prefix
notation, each operator appears before the two operands to which it is to
be applied. Unlike infix notation, Polish prefix notation does not require
the use of brackets to specify the order of the operations. Polish prefix
notation is used in the programming language Lisp.
Finally, we look at post-order traversal. Here, the idea is to visit the
root after visiting each subtree. A recursive algorithm for post-order
traversal is given below:
Algorithm post-order_traverse(T):
1. If T is not a leaf then
1.1. post-order_traverse(left subtree of T)
1.2. post-order_traverse(right subtree of T)
2. Output the root of T

213
Discrete mathematics for computing

Example 11.4.2 Carry out a post-order traversal on the expression tree in Figure 11.8.

Solution The details are similar to those in the previous example, so we just give
the output:
abc/–de+×

An expression written in the form given by the output of a post-order


traversal is said to be written in reverse Polish notation. In reverse Polish
notation, each operator appears after the two operands to which it is to be
applied. Like Polish prefix notation, reverse Polish notation does not
require the use of brackets to specify the order of the operations. Some
calculators use reverse Polish notation – the numbers to be operated on
are entered first (usually with the use of a key labelled ENTER), followed
by the operation (for example, addition).

EXERCISES
1 List the cycles in the graphs shown in Figure 11.9.

Figure 11.9

2 Draw all six trees (up to isomorphism) with six vertices.


3 Draw a tree whose vertices have the following degrees, or explain
why no such tree exists:
(a) seven vertices, with degrees 1, 1, 1, 1, 1, 3, 4;
(b) eight vertices, with degrees 1, 1, 2, 2, 2, 2, 3, 3.
4 A tree has eight vertices of degree 1, three vertices of degree 2,
and two vertices of degree 3. The other vertices all have degree 4.
How many vertices must there be altogether?
5 Find a minimal spanning tree for each of the weighted graphs in
Figure 11.10 (opposite).
6 Write down the weight matrix for each of the weighted graphs in
Exercise 5.
7 The relative costs of building the links between six nodes,
denoted by A, B, C, D, E and F, in a proposed local area network
are tabulated below:

214
Trees

Figure 11.10

A B C D E
B 85
C – 95
D 65 50 –
E 55 – – 70
F 45 – 80 – –

Find the network with the least possible cost that could be built
to link all the nodes in the network.
8 Use Dijkstra’s algorithm to find:
(a) the minimum distance path from C to F in the weighted
graph in Exercise 5(a) (Figure 11.10(a));
(b) the minimum distance path from A to C in the weighted
graph in Exercise 5(b) (Figure 11.10(b)).
9 Construct an expression tree for each of the following
expressions:
(a) a + ((b – c) × d)
(b) ((a × b)/(c × d)) – (e/f)
(c) (a – (b + (c + d))) – ((e × f) × g)
10 By applying a pre-order traversal to the expression tree, write
each of the expressions in Exercise 9 in Polish prefix notation.
11 By applying a post-order traversal to the expression tree, write
each of the expressions in Exercise 9 in reverse Polish notation.
12 Write down (in infix notation) the expressions corresponding to
the trees shown in Figure 11.11 (overleaf).
13 The binary rooted tree shown in Figure 11.12 can be used to
encode and decode English text according to a Huffman code.
The sequence of edges from the root to any letter yields the
binary code for that letter. Note that the number of bits varies
from one letter to another.

215
Discrete mathematics for computing

Figure 11.11

Figure 11.12

(a) Decode 00100110 11101011 11010111 10001010 01011010


11010011 11111100 01111111 10010001 11000.
(The coded message is grouped into strings of eight bits to
enhance readability only; the grouping has no other
significance.)
(b) Encode ‘TO BE OR NOT TO BE’.
(c) What is the advantage of a Huffman code over codes that
use a fixed number of bits for each letter?

216

You might also like