29. Weighted graphs
Graphs (continued)
BFS
Use queue to implement.
public void bfs(Vertex u) {
for (each vertex v in V) { // O(|V|) time
v.visited = false;
}
u.visit(null); // Do some unspecified thing to u
u.visited = true; // Mark the vertex u visited
q = new Queue(); // New queue...
q.enqueue(u); // ...initially containing u
while (q is not empty) { // With adjacency list, O(|E|) time
v = q.dequeue();
for (each vertex w such that (v, w) is an edge in E) {
if (!w.visited) {
w.visit(v); // Do some unspecified thing to w
w.visited = true; // Mark the vertex w visited
q.enqueue(w);
}
}
} public class Vertex {
} protected Vertex parent;
protected int depth;
Notice that when we visit a vertex, protected boolean visited;
we pass the edge's origin vertex
as a parameter. This allows us to public void visit(Vertex origin) {
do a computation such as finding this.parent = origin;
the distance of the vertex from if (origin == null) {
the starting vertex, or finding this.depth = 0;
the shortest path between them. } else {
The visit() method at right this.depth = origin.depth + 1;
accomplishes both these tasks. }
}
}
After we finish, we can find the shortest path from any vertex to the starting vertex by following the parent pointer. These pointers form a tree rooted at the starting vertex.
BFS, like DFS, runs in O(|V| + |E|) time if you use an adjacency list; O(|V|^2) time if you use an adjacency matrix.
Weighted Graphs
In an adjacency matrix, each weight is stored in the matrix. Edges missing from the graph can be represented by a special number like Integer.MIN_VALUE
, at the cost of declaring that number invalid as an edge weight.
In an adjacency list, recall that each edge is represented by a listnode. Each listnode must be enlarged to include a weight, in addition to the reference to the destination vertex.
Two particularly common problems involving weighted graphs.
- shortest path problem. (Application: Suppose a graph represents a highway map, and each road is labeled with the amount of time it takes to drive from one interchange to the next. What's the fastest way to drive from Berkeley to Los Angeles? A shortest path algorithm will tell us.)
- minimum spanning tree. (Application: Suppose that you're wiring a house for electricity. Each node of the graph represents an outlet, or the source of electricity. Every outlet needs to be connected to the source, but not necessarily directly--possibly routed via another outlet. The edges of the graph are labeled with the length of wire you'll need to connect one node to another. How do you connect all the nodes together with the shortest length of wire?)
Kruskal's Algorithm for finding MST
Let G = (V, E) be an undirected graph. A spanning tree T = (V, F) of G is a graph containing the same vertices as G, and |V| - 1 edges of G that form a tree. (Hence, there is exactly one path between any two vertices of T.)
If G is not connected, it has no spanning tree, but we can instead compute a spanning forest, or collection of trees, having one tree for each connected component of G.
Algorithm
[1] Create a new graph T with the same vertices as G, but no edges (yet).
[2] Make a list of all the edges in G.
[3] Sort the edges by weight, from least to greatest.
[4] Iterate through the edges in sorted order.
For each edge (u, w):
[4a] If u and w are not connected by a path in T, add (u, w) to T.
Running Time
- Sorting the edges takes O(|E| log |E|) time
- [4a]? for DFS, the algorithm might take Theta(|E| |V|) time. Can use better ways so that [4a] together take less than O(|E| log |E|) time.
If we use an adjacency list, the running time is in O(|V| + |E| log |E|). But |E| < |V|^2, so log |E| < 2 log |V|. Therefore, Kruskal's algorithm runs in O(|V| + |E| log |V|) time.
If we use an adjacency matrix, the running time is in O(|V|^2 + |E| log |E|), because it takes Theta(|V|^2) time simply to make a list of all the edges.