Graph Algorithms
Download
Report
Transcript Graph Algorithms
Some Graph Algorithms
1. Topological sort
Suppose a project involves doing a number of tasks, but
some of the tasks cannot be done until others are done
Your job is to find a legal order in which to do the tasks
For example, assume:
A must be done before D
B must be done before C, D, or E
D must be done before H
E must be done before D or F
F must be done before C
H must be done before G or I
I must be done before F
Some possible total orderings:
This is a partial ordering
A B E D H I F C G
of the tasks
B A E D H G I F C
A B E D H I G F C
Informal algorithm
Extracting a total ordering from a partial ordering is called
a topological sort
A
B
C
A
Here’s the basic idea:
B
C
Example:
Repeatedly,
Choose a node all of whose
“predecessors” have already
been chosen
D
D
E
F
G
G
H
H
I
I
Only A or B can be chosen. Choose A.
Only B can be chosen. Choose B.
Only E can be chosen. Choose E.
Continue in this manner until all nodes have been chosen.
If all your remaining nodes have predecessors, then there is
a cycle in the data, and no solution is possible
Implementing topological sort
The graph structure can be
implemented in any convenient
way
We need to keep track of the
number of in-edges at each node
Whenever we choose a node, we
need to decrement the number of
in-edges at each of its successors
Since we always want a node with the fewest (zero) inedges, a priority queue seems like a good idea
To remove an element from a priority queue and reheap it
takes O(log n) time
There is a better way
Using buckets
We can start with an array of linked lists; array[n]
points to the linked list of nodes with n in-edges
At each step,
Remove a node N from array[0]
For each node M that N points to,
Get the in-degree d of node M
Remove node M from bucket array[d]
Add node M to bucket array[d-1]
Quit when bucket array[0] is empty
As always, it doesn’t make sense to use a high
efficiency (but more complex) algorithm if the
problem size is small
Bucket example
Buckets:
0 → A B
1 → E G H I
2 → C F
3 → D
Buckets after choosing B:
0 → A E
1 → G H I C
2 → F D
3 →
6
2. Connectivity
Suppose you want to find out quickly (O(1) time) whether it
is possible to get from one node to another in a directed graph
You can use an adjacency matrix to represent the graph
A
E
D
G
B
F
C
A
B
C
D
E
F
G
AB CD EF G
A
B
C
D
E
F
G
AB CD EF G
A connectivity table tells us whether it is possible to get
from one node to another by following one or more edges
Transitive closure
Reachability is transitive: If you can get from A to E, and
you can get from E to G, then you can get from A to G
A
B
C
D
E
F
G
AB CD EF G
A
B
C
D
E
F
G
AB CD EF G
new
Warshall’s algorithm is a systematic method of finding the
transitive closure of a graph
Warshall’s algorithm
Transitivity: If you can get from A to B, and you can
get from B to C, then you can get from A to C
Warshall’s observation: If you can get from A to B
using only nodes with indices less than B, and you can
get from B to C, then you can get from A to C using only
nodes with indices less than B+1
Warshall’s observation makes it possible to avoid most
of the searching that would otherwise be required
Warshall’s algorithm: Implementation
for (i = 1; i <= N; i++) {
for (j = 1; j <= N; j++) {
if (a[j][i]) {
for (k = 1; k <= N; k++) {
if (a[i][k]) a[j][k] = true;
}
}
}
}
It’s easy to see that the running time of this algorithm* is O(N3)
*Algorithm adapted from Algorithms in C by Robert Sedgewick
3. All-pairs shortest path
Closely related to Warshall’s algorithm is Floyd’s
algorithm
Idea: If you can get from A to B at cost c1, and you can
get from B to C with cost c2, then you can get from A to
C with cost c1+c2
Of course, as the algorithm proceeds, if you find a lower
cost you use that instead
The running time of this algorithm is also O(N3)
State graphs
The next couple of algorithms are for state graphs, in
which each node represents a state of the computation, and
the edges between nodes represent state transitions
Example: Thread states in Java
waiting
start
ready
running
dead
The edges should be labelled with the causes of the state
transitions, but in this example they are too verbose
4. Automata
Automata are a formalization of the notion of
state graphs
Each automaton has a start state, one or more
final states, and transitions between states
a
The start
state
A final
state
A state
transition
Operation of an automaton
An automation represents a “program” to accept or reject a
sequence of inputs
It operates as follows:
Start with the “current state” set to the start state and a “read head” at the
beginning of the input string;
While there are still characters in the string:
Read the next character and advance the read head;
From the current state, follow the arc that is labeled with the character just
read; the state that the arc points to becomes the next current state;
When all characters have been read, accept the string if the current state is
a final state, otherwise reject the string.
Example automaton
1
q1
q0 1
0
0
q2 1
1
0
0
q3
Example input string: 1 0 0 1 1 1 0 0
Sample trace: q0 1 q1 0 q3 0 q1 1 q0 1 q1 1 q0 0 q2 0 q0
Since q0 is a final state, the string is accepted
Example automaton
A “hard-wired” automaton
is easy to implement in a
programming language
1
q1
q0 1
0
0
q2 1
1
0
0
q3
• A non-hard-wired automaton
can be implemented as a
directed graph
state := q0;
loop
case state of
q0 : read char;
if eof then accept string;
if char = 0 then state := q2;
if char = 1 then state := q1;
q1 : read char;
if eof then reject string;
if char = 0 then state := q3;
if char = 1 then state := q0;
q2 : read char;
if eof then reject string;
if char = 0 then state := q0;
if char = 1 then state := q3;
q3 : read char;
if eof then reject string;
if char = 0 then state := q1;
if char = 1 then state := q2;
end case;
end loop;
5. Nondeterministic automata
A nondeterministic automaton is one in which there may
be more than one out-edge with the same label
a
A
a
B
etc.
C
A nondeterministic automaton accepts a sequence of inputs
if there is any way to use that string to reach a final state
There are two basic ways to implement a nondeterministic
automaton:
Do a depth-first search, using the inputs to choose the next state
Keep a set of all the states you could be in; for example, starting
from {A} with input a, you would go to {B, C}
6. String searching
Automata can be used to implement efficient string
searching
Example: Search ABAACAAABCAB for ABABC
A
*
0 A 1
C*
B
A
A
*
2
A 3
A
B 4
*
*
The “*” stands for “everything else”
5
The End
19