1 Weighted graphs
1.1 Complete Asymptotic Analysis
1.2 Homework 5 Released
1.3 Directed Weighted Edge
1.4 Index Min PQ
1.5 Worked-out example on handout
1.6 Sample Exam Question
1.7 Version : 2018/ 04/ 22

CS 2223 Apr 24 2018

Lecture Path: 24
Back Next

Expected reading:
Daily Exercise:
Classical selection: Schubert: Symphony No. 5 in B-flat major, D. 485 (1816)
Musical Selection: Barenaked Ladies: One Week (1998)

If you don’t know where you are going, you’ll end up someplace else.
Yogi Berra

1 Weighted graphs

1.1 Complete Asymptotic Analysis

The Big-O Cheat Sheet I mentioned yesterday has some additional parts that I didn’t cover yesterday. We will finish this today.

1.2 Homework 5 Released

Homework 5 is available. Deadline for this assignment is 9PM Monday April 30th. You can demonstrate your knowledge of graphs and BFS/DFS searching with this assignment.

1.3 Directed Weighted Edge

The final extension to the graph structure is assigning numeric weights to each edge. These weights represent various real-world measurements, such as distance, time, or cost.

Associating a weight is nothing more than constructing a structure to keep track of the source and target vertices and the edge weight:

public class DirectedEdge { final int v; final int w; final double weight; public DirectedEdge(int v, int w, double weight) { this.v = v; this.w = w; this.weight = weight; } public int from() { return v; } // Tail vertex of edge public int to() { return w; } // Head vertex of edge public double weight() { return weight; } // Weight of edge /** String representation. */ public String toString() { return v + "->" + w + " " + String.format("%5.2f", vweight); } }

How does this change the landscape? Well, consider the following graph:

If you explore this graph using a Breadth First Strategy, you will see that you can get from vertex 0 to vertex 3 in one edge of weight 10, but if you traverse 0-2-3 over two edges, the accumulated length is 8 which is a shorter path.

We can’t use Depth First Search to find the shortest path. Using Breadth First Search would give the shortest path by total number of edges but not accumulated weight. Clearly we need some other strategy. Let’s be precise:

To guide us in our search, reflect on a simple strategy that you used intuitively on the simple graph: Take action when your current shortest path calculation of s to t is larger than the sum of the distance from s to some vertex x plus the sum of the distance from x to t. To make this work you need to store extra information, but what should it be?

Consider how Breadth First Search constructed an array distTo[v] that recorded the shortest number of edges to traverse from vertex s to vertex v. In our case, use an array dist[v] that records our best computed shortest path from s to each vertex v. You can initialize this array to Infinity for all vertices, other than s which is set to 0.

This is half of the situation. However how can we find some vertex t which grants us a shorter path s-t-v for any vertex v? The answer is to be disciplined in our search.

We need only locate a vertex u that points to t, then we can check to see if dist[u] + weight(u,t) is smaller than dist[t].

Much like Breadth First Search, we will start at a known source vertex, and set its distance to 0 while all other vertices get a computed distance of Infinity. We now place all of these vertices into a Priority Queue that records the shortest known distance to s for any vertex. In our core functioning loop, we retrieve a vertex that has the shortest distance computed from s and we expand from that direction only.

This is directly analagous to the Breadth First Search strategy, this time using the measure of "distance from s" as a means of ordering the vertices in a priority queue.

Once done, the following core loop will serve our purposes. We find a vertex that has shortest distance and remove it from the priority queue and see if we can reduce the computed shortest distances for all of its outgoing adjacent vertices.

while (!pq.isEmpty()) { int v = pq.delMin(); for (DirectedEdge e : G.adj(v)) { relax(e); } }

The definition of relax is as follows, and follows the earlier intuition:

void relax(DirectedEdge e) { int v = e.from(); int w = e.to(); if (distTo[w] > distTo[v] + e.weight()) { distTo[w] = distTo[v] + e.weight(); edgeTo[w] = e; pq.decreaseKey(w, distTo[w]); } }

Now, with this priority queue implementation, we use a special structure known as an IndexMinHeap which takes a basic heap structure and adds a specific capability, namely:

So now you have everything in place. Dijkstra’s algorithm methodically eliminates vertices from consideration one at a time (much like Breadth First Search does by marking vertices as they are encountered). In this case, however, they are "visited" in order of their shortest accumulated path from s. No longer do we mark vertices, but rather we maintain a priority queue of vertices that have yet to be visited. Once the priority queue is empty, we are done.

The details are found in the indexMinPQ class and are worth studying.

1.4 IndexMinPQ

IndexMinPQ is a Java class modified as follows from a standard Min priority queue. It is highly specialize for use with graph algorithms because it can only contain integer values that have an associated priority value (Key).

public class IndexMinPQ<Key extends Comparable<Key>> { int maxN; // maximum number of elements on PQ int N; // number of elements on PQ int[] pq; // binary heap using 1-based indexing int[] qp; // inverse of pq: qp[pq[i]] = pq[qp[i]] = i Key[] keys; // keys[i] = priority of i ... }

This data type supports all priority queue operations with one addition, namely,

public void decreaseKey(int i, Key key) { keys[i] = key; swim(qp[i]); }

This powerful method is trivial to implement. Assuming that you know the given index, i, exists within the PQ, then this operation will reduce its value (wherever it happens to exist in the PQ) and cause it to "swim up" to maintain the heap property of the PQ.

1.5 Worked-out example on handout

You can show the structure of a graph from a text file

% java algs.days.day23.DigraphAdjacencyList day24.txt

To launch the example today, just run algs.days.day23.DijkstraSP which is pre-configured to execute this small example.

1.6 Sample Exam Question

You add the following numbers to an empty AVL tree in this order: 1, 2, 3, 4, 5 What is the structure of the tree?

Here is a more difficult question:

To an empty AVL tree, you add the numbers 1, 2, 3, ... , 2^k-1 for some positive k. What is the value of the root node?

1.7 Version : 2018/04/22

(c) 2018, George Heineman