Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Algorithms
An Introduction To Graphs, Part 2
Alfresco
B efore I continue with my intro-
duction to graphs, one of my
readers was kind enough to point
graph). We provided three
different ways of storing a graph in
memory: as a matrix, a triangular
out that Ive become unreachable. matrix (not for digraphs though),
For the past few articles, Ive or an array of linked lists. Finally,
neglected to add my email address we looked at depth-first traversals.
to the mini-bio at the end of the Phew! After that quick rsum,
article. Oops, sorry about that, it lets move on (of course, if youve by Julian Bucknall
wasnt my intention to become forgotten some of the above,
incommunicado. You can of please quickly go over Octobers Why would we want to do this
course reach me by sending a mes- column and meet us back here). (ie, visit all nodes in a depth-first
sage to julianb@turbopower.com fashion)? There is a neat algorithm
or to our Esteemed Editor, who will Topological Sorts that falls out from such a
forward it if need be. And please do One of the things I didnt really depth-first traversal called a topo-
drop me a line; that includes touch on with my previous discus- logical sort. Suppose we have a set
compliments, brickbats, errors in sion was a depth-first traversal of of tasks that need to be done. Cer-
text or code etc. If your message all the nodes in unconnected tain of these tasks require others
makes a valid point, Ill be sure to graphs. The depth-first traversal to be performed first, in other
include it in a sidebar in a future weve seen so far finds all the words they have prerequisites.
article. nodes that can be visited from a Examples of this are developing a
Anyway, onwards with graphs, given source node. It is entirely computer program (we need to
since we have a lot to cover. You possible that some nodes in the design the database before writing
may recollect that in the October graph would not be visited by such the code, we have to decide on the
1998 instalment of Algorithms a traversal. If this is the case, we data items were going to track
Alfresco, we talked about the graph call the graph unconnected. With a before we design the database, the
structure. We learned that a graph non-directed graph its generally install program comes last of all,
consists of a set of nodes (or verti- simple to see if a graph is after all the EXEs and DLLs are fin-
ces) connected together by edges. unconnected by looking at its pic- ished), devising a recipe for choco-
The edges could be either two way ture: basically the graph falls into late chip cookies (we can only put
(if there was an edge between node two or more sub-graphs with no the cookies in the oven after weve
A and node B then there is an edge edges connecting them. For a mixed the cookie dough), getting
between B and A, the same one) or digraph, in many cases its not dressed (we have to put on our
the edges were directed (if there obvious. If we wanted to visit abso- underwear first, unless we happen
was an edge from A to B then it lutely every node, wed start out to be Superman) and so on. Trans-
does not follow that there is an from the first node and do a lating this into nodes and edges in
edge from B to A, we can think of depth-first traversal on that, then our graph vernacular: a node is a
the edge having an arrowhead wed look for a node that hasnt task, an edge is directed and shows
showing the direction of the edge). been visited and do a depth-first the prerequisite attribute (its from
The latter kind of graph is known as traversal on that. Wed continue node task must be performed
a digraph (or directed graph). Both this process until all the nodes had before its to node task and the
nodes and edges could contain been visited. Listing 1 shows arrow points towards the to node).
data (if an edge contains data it is ExecuteAll, the implementation of A topological sort organizes the
usually known as a weighted this algorithm. tasks in order so that prerequisites
are done before their dependent
tasks. An important restriction
Listing 1: Depth-first ExecuteAll method.
must be made on the graph first: it
procedure TaaDepthFirstIterator.ExecuteAll( must have no cycles; in other
var aHasCycle : boolean; aExtraData : pointer);
var words, it must be a directed acy-
i : integer; clic graph, also known as a dag.
ithHasCycle : boolean;
begin Whats a cycle? Well a cycle is
aHasCycle := false;
for i := 0 to pred(dfiGraph.NodeCount) do begin when you start from a node, visit
if (PitrCounter(dfiNodes[i])^.cMarker = 0) then begin
Execute(i, ithHasCycle, aExtraData);
nodes along directed edges, and
aHasCycle := aHasCycle or ithHasCycle; get right back where you started
end;
end; from (see Figure 1). If you think in
end;
terms of tasks and prerequisites,
Listing 3:
post-process when the node is iterator does, we can easily print
The Execute method for the
actually visited and the edges out the shortest path by walking
breadth-first iterator class.
from it are then followed. backwards following these back-
ward links. We can use recursion
nodes weve visited, instead of a Shortest Path or an explicit stack to print out the
stack. Another thing to notice about the path in the correct order (every
Again, just like in the depth-first breadth-first traversal is that it time we move backwards from a
traversal case, well define a sepa- gives you the shortest path from given node we push the parent
rate class to perform a breadth- the source node to every other node onto a stack until we reach
first traversal. This provides isola- node. By shortest path, I mean the the source node; now we pop the
tion of the iterator from the class number of edges that have to be nodes off the stack and print them
used to store the graph and hence followed to get from the source out to give the shortest path).
enables a breadth-first iterator node to a given node (well be Listing 4 gives the details where we
object to work with any graph seeing another definition of short- are using the program stack
object descended from our original est path for a weighted graph in a implicitly through recursion.
graph class. The design is a little minute). We can see this in a Notice how we first traverse the
more tricky than before because not-very-rigorous fashion by whole graph from the given index,
we have to code up a queue as well, visualizing the breadth-first search and then we print out the shortest
but its pretty easy to follow. Like as proceeding in waves or rip- path to the given index by walking
before, well have a pre-process ples from the source nodes. First backwards (since nodes are
and a post-process event so that all the immediate neighbor nodes untyped we require an extra rou-
you have control over when you are visited (their shortest paths tine to print a node: this routine
want to do some work with a node are all of length 1), the first wave. could print the name or identifier
being visited. The interface for the Then all their neighbors are vis- of the node, for example). It could
breadth-first iterator is roughly the ited, the second wave, and their very well be that there is no path
same as for the depth-first iterator shortest path distances are of from the source node to the target
from last time, and the code for the length 2. And so on, so forth, node (in which case well hit a
Execute method is shown in Listing rippling outwards. dead end on a node without a
3. Figure 3 shows the steps taken in In fact, if we make note of the predecessor in our backwards
a breadth-first traversal for a parent (or predecessor) node of walk), so we ought to report that
sample digraph (its the one in each node as we traverse the fact as well. The implementation
Figure 2 of Octobers article, so you graph, which youll notice that the makes the shortest path routine a
can compare the depth-first and
breadth-first traversals).
Figure 3: Breadth-first traversal, step-by-step.
If you look at Listing 3, youll see
that the pre-process event gets A A A A B A B
fired just as the node gets added to
D E D E D E D C
the queue, and the post-process
event when the node is popped off
A B A B
the queue. In other words,
pre-process is when the node is E D C E D C
first seen from the vantage point
of its predecessor node, and G F G
Listing 4:
and the priority queue class from first. The main traversal method
The unweighted shortest path.
Novembers Algorithms Alfresco. for solving weighted graph
Before we start we must make a algorithms is priority-first. The
function: it returns True if a path couple of important assumptions. previous two used a stack and a
was found, False if not. In my original graph class I allowed queue respectively; the priority-
All right! Time for a breather. Up an edge to be weighted with a first traversal uses a priority
to this point weve discussed (in typeless pointer. Since our code up queue (seems obvious, no?). The
depth) graph representations, to now hasnt had to worry about traversal works by taking the edge
depth-first traversals and breadth- what data structure these typeless with the largest priority (however
first traversals. We really ought to pointers point to, we havent wor- that may be defined). Note that I
move onto some heavyweight ried about it too much. Well, now is didnt say cost or weight, but prior-
algorithms, otherwise our the time to worry about it. For the ity. Well see a couple of different
Esteemed Editor will be wondering algorithms that follow we need to ways of calculating the priority in a
whether Im losing touch! lay down a couple of rules. Rule 1 is moment for different algorithms.
that we need to be able to take two What happens in a priority-first
Weighted Graph Algorithms edge weights and state whether traversal is this:
Lets now consider weighted the first is less than, equal to, or 1. Mark the starting node as
graphs. If you recall, a weighted greater than the second. The preprocessed.
graph is a graph where each edge weights have to be sortable, in 2. Compute the priority of the
has a weight or a cost associated other words. Rule 2 is even more starting node.
with it. An obvious example is a strict: given two edge weights, we 3. Insert it into the priority
map where the cities and towns are need to be able to add them queue.
the nodes and the roads between together. In other words we need 4. Remove the node with the
them are the edges of a graph. If we to calculate the total cost of going maximum priority from the queue,
denote the cost of an edge as from node X to node Y and then on mark it as postprocessed. Follow
being the average time it would to node Z. These two rules pretty each edge from that node.
take to travel along that road, we well force us to assume that the 5. If an edge leads to a node that
can then start asking questions like weight of an edge is numeric. We hasnt been visited yet, mark the
which journey between city X and shall assume that edge weights are node as preprocessed, calculate
city Y would take the smallest time of type longint from now on (the its priority and insert it into the pri-
and through which other cities code on the disk has been changed ority queue.
must we pass? Or, which tour that to reflect this). 6. If the edge leads to a
starts and ends at city X and visits The next assumption is less preprocessed node, the node is in
each and every city once would strict. One of the algorithms we the priority queue already, so cal-
take the shortest time? shall meet in a minute (Dijkstras culate the new priority of the node
If, instead, the cost of an edge algorithm) only works if the (it might have changed because of
was the distance along the road, weights are never negative. Well the different path weve taken),
and we wished to lay our high see why in a moment, but for now find the node in the priority queue
bandwidth high cost optical cable well embrace this assumption as and change the priority if the new
to connect primary hubs in all of well. value is larger than the old. Update
the cities, along which roads So, edge weights are non- the priority queue, if so.
should we lay it to minimize the negative longint values. 7. If the priority queue is not
amount of cable? empty, return to step 4.
These types of problems are Priority-First Traversals If you think back to Novembers
solvable by using weighted graphs, The two traversals weve seen so Algorithms Alfresco column for a
a couple of important algorithms far are depth-first and breadth- moment, I deliberately introduced
5 5
a b a b
15 20 15 20
15 10 15 10
e c e c
20 d 25 20 d 25
Listing 5:
function EvalPrimsPriority(aSender : TObject; aFromIndex : integer;
The Execute method for the aEdgeCost : longint; aToIndex : integer) : longint;
priority-first iterator class. begin
Result := aEdgeCost;
end;
procedure MinSpanningTree(aGraph : TaaGraph; aProcessNode : TaaProcessNode;
do is to return the cost of the edge aExtraData : pointer);
var
leading to the node. Iter : TaaPriorityFirstIterator;
begin
Iter := TaaPriorityFirstIterator.Create(aGraph);
Iter.OnPostProcess := aProcessNode;
Travelling Salesmen Problems try
What is so special about Prims Iter.Execute(EvalPrimsPriority, 0, aExtraData);
finally
algorithm and minimum spanning Iter.Free;
end;
trees? Well, theyre used in travell- end;
ing salesmen type problems.
Suppose that a salesman has a
Listing 6: Prim's algorithm.
set of stores that he must visit in Believe it or not, solving this
order to demonstrate and sell his type of problem generically is diffi-
companys latest widget. It makes cult in the extreme. Actually, lets the minimum. Suppose now that
sense for him to minimize the rephrase that. Although the solu- there are 10 different stores to
amount of time it takes him to tion is simple to state (list all the visit. This time hed have to find
travel between these stores so that possible tours and select the one the minimal tour in a set of 10! or
he can take the rest of the day off with the smallest cost), the prob- 3,628,800 possibilities. This is get-
(and indeed to make sure that he lem that arises is the number of ting a little unwieldy, but if his boss
has some time to take off!). Using possible tours increases exponen- had given him a PC that could cal-
his knowledge of the traffic in his tially with the number of nodes and culate the cost of 100,000 tours a
city, where these stores are, the edges. In our salesman problem, second itd take about 40 seconds
one-way systems, etc, he can draw suppose that there were 5 possible to find the minimum one. If there
up a graph with the stores as nodes stores and that he could go from were 15 stores then there would be
and the cost of the edge between any store to any other. He starts off 1,307,674,368,000 different tours in
two nodes the time it would take to at the factory, has a choice of 5 all, which would take about 151
go from one store to the other. It is stores to visit first, then a choice of days to calculate the minimal one
assumed that he can get from any 4 stores to visit next, and so on on his little PC. This is just not
store to any other without passing until hes visited the last store and feasible.
through a third (the graph repre- then returns to the factory. There The travelling salesman prob-
senting the map of the stores and are 5! different possible tours he lem is one of a set of NP-complete
roads is said to be complete). How could make, and thats 120. Calcu- problems (where NP means non-
does he calculate a tour of the lating the cost of each tour is pretty deterministic polynomial-time).
stores that will take the minimum simple and it wouldnt take too The main characteristic of all
time? long to calculate them all and find these problems is that the running