Data Structures, Algorithms, & Applications in Java
Chapter 18, Exercise 35
We need to perform the following operations on the
d values: select the as yet unselected vertex
with minimum
d value,
decrease some distance values. These operations
are done fairly efficiently
using a min heap which is augmented by an array
location to keep track of the
location in heap[] of the distance
value of a vertex.
Therefore, we begin by
defining the class ModifiedMinHeap.
The invocation decreaseWeight(x) replaces the
old distance (weight) of vertex x.vertex
by the smaller value x.weight.
The method initialize has not been implemented.
Although the code given below stores weighted edge nodes in the min heap,
it is sufficient to store only the weights.
public class ModifiedMinHeap
{
// data members
WeightedEdgeNode [] heap; // array for complete binary tree
int [] location; // current location of an element
int size; // number of elements in heap
// constructors
/** create a heap with the given initial capacity */
public ModifiedMinHeap(int initialCapacity)
{
if (initialCapacity < 1)
throw new IllegalArgumentException
("initialCapacity must be >= 1");
heap = new WeightedEdgeNode [initialCapacity + 1];
location = new int [initialCapacity + 1];
size = 0;
}
/** create a heap with initial capacity 10 */
public ModifiedMinHeap()
{this(10);}
// methods
/** @return true iff the heap is empty */
public boolean isEmpty()
{return size == 0;}
/** @return number of elements in the heap */
public int size()
{return size;}
/** @return minimum element
* @return null if the heap is empty */
public WeightedEdgeNode getMin()
{
if (size == 0)
return null;
else
return heap[1];
}
/** put theElement into the heap */
public void put(WeightedEdgeNode theElement)
{
// increase array size if necessary
if (size == heap.length - 1)
heap = (WeightedEdgeNode []) ChangeArrayLength.changeLength1D
(heap, 2 * heap.length);
// find place for theElement
// i starts at new leaf and moves up tree
int i = ++size;
while (i != 1 && ((Comparable) heap[i/2].weight)
.compareTo(theElement.weight) > 0)
{
// cannot put theElement in heap[i]
heap[i] = heap[i/2]; // move element down
location[heap[i].vertex] = i;
i /= 2; // move to parent
}
heap[i] = theElement;
location[theElement.vertex] = i;
}
/** remove min element and return it */
public WeightedEdgeNode removeMin()
{
// if heap is empty return null
if (size == 0) return null; // heap empty
WeightedEdgeNode x = heap[1]; // min element
location[x.vertex] = 0;
// restucture heap
WeightedEdgeNode y = heap[size--]; // last element
// find place for y starting at root
int i = 1, // current node of heap
ci = 2; // child of i
while (ci <= size)
{
// heap[ci] should be smaller child of i
if (ci < size && ((Comparable) heap[ci].weight)
.compareTo(heap[ci+1].weight) > 0)
ci++;
// can we put y in heap[i]?
if (((Comparable) y.weight).compareTo(heap[ci].weight) <= 0)
break; // yes
// no
heap[i] = heap[ci]; // move child up
location[heap[i].vertex] = i;
i = ci; // move down a level
ci *= 2;
}
heap[i] = y;
location[y.vertex] = i;
return x;
}
/** decrease weight of x.vertex to x.weight */
public void decreaseWeight(WeightedEdgeNode x)
{
// check if x.vertex in heap
if (location[x.vertex] == 0)
// not in heap
throw new IllegalArgumentException
("illegal id value");
// make sure new distance is smaller
if (((Comparable) x.weight)
.compareTo(heap[location[x.vertex]].weight) >= 0)
throw new IllegalArgumentException
("new distance value must be less than old one");
// find new place for x
// i starts at old location of x and moves up tree
int i = location[x.vertex];
while (i != 1 && ((Comparable) x.weight)
.compareTo(heap[i/2].weight) < 0)
{// cannot put x in heap[i]
heap[i] = heap[i/2]; // move element down
location[heap[i].vertex] = i;
i /= 2; // move to parent
}
heap[i] = x;
location[x.vertex] = i;
}
}
The shortest paths code now takes the form
given below.
public class LinkedWDigraphWithShortestPaths2 extends LinkedWDigraph
{
// constructors
public LinkedWDigraphWithShortestPaths2(int theVertices)
{super(theVertices);}
// default is a 0 vertex graph
public LinkedWDigraphWithShortestPaths2()
{this(0);}
/** find shortest paths from vertex s
* @return shortest distances in d
* @return predecessor information in p */
public void shortestPathsUsingAHeap(int s, Operable [] d, int [] p)
{
if (s < 1 || s > n)
throw new IllegalArgumentException
("source vertex cannot be " + s);
ModifiedMinHeap heap = new ModifiedMinHeap(); // min heap of d values
// for reachable vertices for which a path is yet to be generated
// initialize d, p, and l
// first set all d values to null and all p values to -1
for (int i = 1; i <= n; i++)
{
d[i] = null;
p[i] = -1;
}
// now change d and p values for vertices adjacent from s
Iterator is = aList[s].iterator();
while (is.hasNext())
{
WeightedEdgeNode wNode = (WeightedEdgeNode) is.next();
d[wNode.vertex] = (Operable) wNode.weight;
d[s] = (Operable) ((Operable) wNode.weight).zero();
p[wNode.vertex] = s;
heap.put(new WeightedEdgeNode(wNode.vertex, d[wNode.vertex]));
}
p[s] = 0; // source vertex has no predecessor
// update d and p
while (!heap.isEmpty())
{// more paths exist
// extract vertex v with least d from the min heap
int v = ((WeightedEdgeNode) heap.removeMin()).vertex;
// next shortest path is to vertex v
// update d values
Iterator iv = aList[v].iterator();
while (iv.hasNext())
{
WeightedEdgeNode wNode = (WeightedEdgeNode) iv.next();
int j = wNode.vertex;
if (p[j] == -1 || d[j].compareTo(d[v].add(wNode.weight)) > 0)
{
// d[j] decreases
d[j] = (Operable) d[v].add(wNode.weight);
// add j to heap if not already there, else update heap entry
if (p[j] == -1)
// j is not in the min heap
heap.put(new WeightedEdgeNode(j, d[j]));
else
// j is in the min heap
heap.decreaseWeight(new WeightedEdgeNode(j, d[j]));
p[j] = v;
}
}
}
}
}
Sine the digraph has O(n) edges, the time spent performing
heap operations is O(n log n), and the time spent in the
remainder of the code is O(n + e) = O(n).
So, the overall complexity is O(n log n).