Article View: comp.lang.prolog
Article #3239Re: Wierd Topological Sort
From: Richard A. O'Keefe
Date: Thu, 14 Apr 1988 07:53
Date: Thu, 14 Apr 1988 07:53
66 lines
2971 bytes
2971 bytes
In article <5224@sdcrdcf.UUCP>, markb@sdcrdcf.UUCP (Mark Biggar) writes:
> I have a problem where I need to do a topological sort on the nodes of a
> directed graph. This would be simple except that the graphs can contain
> cycles. It is the nature of the problem then each node has only ONE
> edge leaving it, but may have several edges leading to it. This means
> that any connected subgraph can have at most one cycle in it. I wish to
> treat these cycles as single nodes in the sorted list.
>
> So if I have a list of directed edges like:
>
> [d(e,a),d(b,c),d(f,b),d(a,c),d(d,e),d(c,e)]
>
> I get the result:
>
> [[e,a,c],b,f,d] (or some other permutation that is a valid topological sort)
>
> The graphs I am working with may have several disjoint pieces (each of which
> may contain a cycle).
>
There are two parts to the question: how do you do this at all, and how
do you do it in Prolog. The Prolog part isn't terribly interesting, there
is code for topological sort and union/find already drifting around. So
I'll concentrate on the first part.
Such a graph is a sort of forest, except that some of the "trees" have
a ring as their root instead of a single node.
The best method I can think of is to adapt the usual Depth-First-Search
method for determining strongly connected components.
for Node in nodes(Graph) do visited(Node) := false od
Order := []
for Node in nodes(Graph) do if not visited(Node) then
Stack := [] % all the nodes reachable from Node
N := Node
while not visited(N) and there is an arc N->P do
visited(N) := true
Stack := [N|Stack]
N := P
od
if visited(N) then
% either we've found a cycle, or a previously processed path
if member(N, Stack) then
% it's a cycle
Cycle := []
repeat Cycle,Stack := [head(Stack)|Cycle], tail(Stack)
until head(Cycle) = N
Order := [[Cycle]|Order]
fi
else
% we've found a plain root
visited(N) := true
Stack := [N|Stack]
fi
Order := append(Stack, Order)
fi od
Order := reverse(Order)
Interestingly enough, we can use ordinary lists for Stack, Cycle, and Order.
If the member(N, Stack) test takes k steps, so what? It must have taken at
least k steps to make Stack in the first place, so using ordinary member/2
won't spoil the asymptotic efficiency. The trick is representing visited()
and the collection of arcs. That's what will make this an O(V.lgV) method
in Prolog (V being the number of vertices) rather than an O(V) method.
Caveat: I haven't tested this code.
Technical Details
Message-ID:
<876@cresswell.quintus.UUCP>Path:
arc1-ca.pugleaf.net!utzoo!mnetor!uunet!lll-winken!lll-tis!mordor!sri-spam!sri-unix!quintus!okReferences:
<5224@sdcrdcf.UUCP>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!mnetor!uunet!lll-winken!lll-tis!mordor!sri-spam!sri-unix!quintus!ok From: ok@quintus.UUCP (Richard A. O'Keefe) Newsgroups: comp.lang.prolog Subject: Re: Wierd Topological Sort Message-ID: <876@cresswell.quintus.UUCP> Date: 14 Apr 88 07:53:56 GMT References: <5224@sdcrdcf.UUCP> Organization: Quintus Computer Systems, Mountain View, CA Lines: 65