【转】Fibonacci 斐波纳契堆优化 Dijkstra 最短路径算法

 话不多说,拿来主义,直接上代码!

PS:打印最短路径我还不晓得怎么加,如有哪位大神知道,还请mark一下!

  1 /***********************************************************************
  2  * File: FibonacciHeap.java
  3  * Author: Keith Schwarz (htiek@cs.stanford.edu)
  4  *
  5  * An implementation of a priority queue backed by a Fibonacci heap,
  6  * as described by Fredman and Tarjan.  Fibonacci heaps are interesting
  7  * theoretically because they have asymptotically good runtime guarantees
  8  * for many operations.  In particular, insert, peek, and decrease-key all
  9  * run in amortized O(1) time.  dequeueMin and delete each run in amortized
 10  * O(lg n) time.  This allows algorithms that rely heavily on decrease-key
 11  * to gain significant performance boosts.  For example, Dijkstra's algorithm
 12  * for single-source shortest paths can be shown to run in O(m + n lg n) using
 13  * a Fibonacci heap, compared to O(m lg n) using a standard binary or binomial
 14  * heap.
 15  *
 16  * Internally, a Fibonacci heap is represented as a circular, doubly-linked
 17  * list of trees obeying the min-heap property.  Each node stores pointers
 18  * to its parent (if any) and some arbitrary child.  Additionally, every
 19  * node stores its degree (the number of children it has) and whether it
 20  * is a "marked" node.  Finally, each Fibonacci heap stores a pointer to
 21  * the tree with the minimum value.
 22  *
 23  * To insert a node into a Fibonacci heap, a singleton tree is created and
 24  * merged into the rest of the trees.  The merge operation works by simply
 25  * splicing together the doubly-linked lists of the two trees, then updating
 26  * the min pointer to be the smaller of the minima of the two heaps.  Peeking
 27  * at the smallest element can therefore be accomplished by just looking at
 28  * the min element.  All of these operations complete in O(1) time.
 29  *
 30  * The tricky operations are dequeueMin and decreaseKey.  dequeueMin works
 31  * by removing the root of the tree containing the smallest element, then
 32  * merging its children with the topmost roots.  Then, the roots are scanned
 33  * and merged so that there is only one tree of each degree in the root list.
 34  * This works by maintaining a dynamic array of trees, each initially null,
 35  * pointing to the roots of trees of each dimension.  The list is then scanned
 36  * and this array is populated.  Whenever a conflict is discovered, the
 37  * appropriate trees are merged together until no more conflicts exist.  The
 38  * resulting trees are then put into the root list.  A clever analysis using
 39  * the potential method can be used to show that the amortized cost of this
 40  * operation is O(lg n), see "Introduction to Algorithms, Second Edition" by
 41  * Cormen, Rivest, Leiserson, and Stein for more details.
 42  *
 43  * The other hard operation is decreaseKey, which works as follows.  First, we
 44  * update the key of the node to be the new value.  If this leaves the node
 45  * smaller than its parent, we're done.  Otherwise, we cut the node from its
 46  * parent, add it as a root, and then mark its parent.  If the parent was
 47  * already marked, we cut that node as well, recursively mark its parent,
 48  * and continue this process.  This can be shown to run in O(1) amortized time
 49  * using yet another clever potential function.  Finally, given this function,
 50  * we can implement delete by decreasing a key to -infty, then calling
 51  * dequeueMin to extract it.
 52  */
 53 
 54 import java.util.*; // For ArrayList
 55 
 56 /**
 57  * A class representing a Fibonacci heap.
 58  *
 59  * @param T The type of elements to store in the heap.
 60  * @author Keith Schwarz (htiek@cs.stanford.edu)
 61  */
 62 public final class FibonacciHeap<T> {
 63     /* In order for all of the Fibonacci heap operations to complete in O(1),
 64      * clients need to have O(1) access to any element in the heap.  We make
 65      * this work by having each insertion operation produce a handle to the
 66      * node in the tree.  In actuality, this handle is the node itself, but
 67      * we guard against external modification by marking the internal fields
 68      * private.
 69      */
 70     public static final class Entry<T> {
 71         private int     mDegree = 0;       // Number of children
 72         private boolean mIsMarked = false; // Whether this node is marked
 73 
 74         private Entry<T> mNext;   // Next and previous elements in the list
 75         private Entry<T> mPrev;
 76 
 77         private Entry<T> mParent; // Parent in the tree, if any.
 78 
 79         private Entry<T> mChild;  // Child node, if any.
 80 
 81         private T      mElem;     // Element being stored here
 82         private double mPriority; // Its priority
 83 
 84         /**
 85          * Returns the element represented by this heap entry.
 86          *
 87          * @return The element represented by this heap entry.
 88          */
 89         public T getValue() {
 90             return mElem;
 91         }
 92         /**
 93          * Sets the element associated with this heap entry.
 94          *
 95          * @param value The element to associate with this heap entry.
 96          */
 97         public void setValue(T value) {
 98             mElem = value;
 99         }
100 
101         /**
102          * Returns the priority of this element.
103          *
104          * @return The priority of this element.
105          */
106         public double getPriority() {
107             return mPriority;
108         }
109 
110         /**
111          * Constructs a new Entry that holds the given element with the indicated 
112          * priority.
113          *
114          * @param elem The element stored in this node.
115          * @param priority The priority of this element.
116          */
117         private Entry(T elem, double priority) {
118             mNext = mPrev = this;
119             mElem = elem;
120             mPriority = priority;
121         }
122     }
123 
124     /* Pointer to the minimum element in the heap. */
125     private Entry<T> mMin = null;
126 
127     /* Cached size of the heap, so we don't have to recompute this explicitly. */
128     private int mSize = 0;
129 
130     /**
131      * Inserts the specified element into the Fibonacci heap with the specified
132      * priority.  Its priority must be a valid double, so you cannot set the
133      * priority to NaN.
134      *
135      * @param value The value to insert.
136      * @param priority Its priority, which must be valid.
137      * @return An Entry representing that element in the tree.
138      */
139     public Entry<T> enqueue(T value, double priority) {
140         checkPriority(priority);
141 
142         /* Create the entry object, which is a circularly-linked list of length
143          * one.
144          */
145         Entry<T> result = new Entry<T>(value, priority);
146 
147         /* Merge this singleton list with the tree list. */
148         mMin = mergeLists(mMin, result);
149 
150         /* Increase the size of the heap; we just added something. */
151         ++mSize;
152 
153         /* Return the reference to the new element. */
154         return result;
155     }
156 
157     /**
158      * Returns an Entry object corresponding to the minimum element of the
159      * Fibonacci heap, throwing a NoSuchElementException if the heap is
160      * empty.
161      *
162      * @return The smallest element of the heap.
163      * @throws NoSuchElementException If the heap is empty.
164      */
165     public Entry<T> min() {
166         if (isEmpty())
167             throw new NoSuchElementException("Heap is empty.");
168         return mMin;
169     }
170 
171     /**
172      * Returns whether the heap is empty.
173      *
174      * @return Whether the heap is empty.
175      */
176     public boolean isEmpty() {
177         return mMin == null;
178     }
179 
180     /**
181      * Returns the number of elements in the heap.
182      *
183      * @return The number of elements in the heap.
184      */
185     public int size() {
186         return mSize;
187     }
188 
189     /**
190      * Given two Fibonacci heaps, returns a new Fibonacci heap that contains
191      * all of the elements of the two heaps.  Each of the input heaps is
192      * destructively modified by having all its elements removed.  You can
193      * continue to use those heaps, but be aware that they will be empty
194      * after this call completes.
195      *
196      * @param one The first Fibonacci heap to merge.
197      * @param two The second Fibonacci heap to merge.
198      * @return A new FibonacciHeap containing all of the elements of both
199      *         heaps.
200      */
201     public static <T> FibonacciHeap<T> merge(FibonacciHeap<T> one, FibonacciHeap<T> two) {
202         /* Create a new FibonacciHeap to hold the result. */
203         FibonacciHeap<T> result = new FibonacciHeap<T>();
204 
205         /* Merge the two Fibonacci heap root lists together.  This helper function
206          * also computes the min of the two lists, so we can store the result in
207          * the mMin field of the new heap.
208          */
209         result.mMin = mergeLists(one.mMin, two.mMin);
210 
211         /* The size of the new heap is the sum of the sizes of the input heaps. */
212         result.mSize = one.mSize + two.mSize;
213 
214         /* Clear the old heaps. */
215         one.mSize = two.mSize = 0;
216         one.mMin  = null;
217         two.mMin  = null;
218 
219         /* Return the newly-merged heap. */
220         return result;
221     }
222 
223     /**
224      * Dequeues and returns the minimum element of the Fibonacci heap.  If the
225      * heap is empty, this throws a NoSuchElementException.
226      *
227      * @return The smallest element of the Fibonacci heap.
228      * @throws NoSuchElementException If the heap is empty.
229      */
230     public Entry<T> dequeueMin() {
231         /* Check for whether we're empty. */
232         if (isEmpty())
233             throw new NoSuchElementException("Heap is empty.");
234 
235         /* Otherwise, we're about to lose an element, so decrement the number of
236          * entries in this heap.
237          */
238         --mSize;
239 
240         /* Grab the minimum element so we know what to return. */
241         Entry<T> minElem = mMin;
242 
243         /* Now, we need to get rid of this element from the list of roots.  There
244          * are two cases to consider.  First, if this is the only element in the
245          * list of roots, we set the list of roots to be null by clearing mMin.
246          * Otherwise, if it's not null, then we write the elements next to the
247          * min element around the min element to remove it, then arbitrarily
248          * reassign the min.
249          */
250         if (mMin.mNext == mMin) { // Case one
251             mMin = null;
252         }
253         else { // Case two
254             mMin.mPrev.mNext = mMin.mNext;
255             mMin.mNext.mPrev = mMin.mPrev;
256             mMin = mMin.mNext; // Arbitrary element of the root list.
257         }
258 
259         /* Next, clear the parent fields of all of the min element's children,
260          * since they're about to become roots.  Because the elements are
261          * stored in a circular list, the traversal is a bit complex.
262          */
263         if (minElem.mChild != null) {
264             /* Keep track of the first visited node. */
265             Entry<?> curr = minElem.mChild;
266             do {
267                 curr.mParent = null;
268 
269                 /* Walk to the next node, then stop if this is the node we
270                  * started at.
271                  */
272                 curr = curr.mNext;
273             } while (curr != minElem.mChild);
274         }
275 
276         /* Next, splice the children of the root node into the topmost list, 
277          * then set mMin to point somewhere in that list.
278          */
279         mMin = mergeLists(mMin, minElem.mChild);
280 
281         /* If there are no entries left, we're done. */
282         if (mMin == null) return minElem;
283 
284         /* Next, we need to coalsce all of the roots so that there is only one
285          * tree of each degree.  To track trees of each size, we allocate an
286          * ArrayList where the entry at position i is either null or the 
287          * unique tree of degree i.
288          */
289         List<Entry<T>> treeTable = new ArrayList<Entry<T>>();
290 
291         /* We need to traverse the entire list, but since we're going to be
292          * messing around with it we have to be careful not to break our
293          * traversal order mid-stream.  One major challenge is how to detect
294          * whether we're visiting the same node twice.  To do this, we'll
295          * spent a bit of overhead adding all of the nodes to a list, and
296          * then will visit each element of this list in order.
297          */
298         List<Entry<T>> toVisit = new ArrayList<Entry<T>>();
299 
300         /* To add everything, we'll iterate across the elements until we
301          * find the first element twice.  We check this by looping while the
302          * list is empty or while the current element isn't the first element
303          * of that list.
304          */
305         for (Entry<T> curr = mMin; toVisit.isEmpty() || toVisit.get(0) != curr; curr = curr.mNext)
306             toVisit.add(curr);
307 
308         /* Traverse this list and perform the appropriate unioning steps. */
309         for (Entry<T> curr: toVisit) {
310             /* Keep merging until a match arises. */
311             while (true) {
312                 /* Ensure that the list is long enough to hold an element of this
313                  * degree.
314                  */
315                 while (curr.mDegree >= treeTable.size())
316                     treeTable.add(null);
317 
318                 /* If nothing's here, we're can record that this tree has this size
319                  * and are done processing.
320                  */
321                 if (treeTable.get(curr.mDegree) == null) {
322                     treeTable.set(curr.mDegree, curr);
323                     break;
324                 }
325 
326                 /* Otherwise, merge with what's there. */
327                 Entry<T> other = treeTable.get(curr.mDegree);
328                 treeTable.set(curr.mDegree, null); // Clear the slot
329 
330                 /* Determine which of the two trees has the smaller root, storing
331                  * the two tree accordingly.
332                  */
333                 Entry<T> min = (other.mPriority < curr.mPriority)? other : curr;
334                 Entry<T> max = (other.mPriority < curr.mPriority)? curr  : other;
335 
336                 /* Break max out of the root list, then merge it into min's child
337                  * list.
338                  */
339                 max.mNext.mPrev = max.mPrev;
340                 max.mPrev.mNext = max.mNext;
341 
342                 /* Make it a singleton so that we can merge it. */
343                 max.mNext = max.mPrev = max;
344                 min.mChild = mergeLists(min.mChild, max);
345                 
346                 /* Reparent max appropriately. */
347                 max.mParent = min;
348 
349                 /* Clear max's mark, since it can now lose another child. */
350                 max.mIsMarked = false;
351 
352                 /* Increase min's degree; it now has another child. */
353                 ++min.mDegree;
354 
355                 /* Continue merging this tree. */
356                 curr = min;
357             }
358 
359             /* Update the global min based on this node.  Note that we compare
360              * for <= instead of < here.  That's because if we just did a
361              * reparent operation that merged two different trees of equal
362              * priority, we need to make sure that the min pointer points to
363              * the root-level one.
364              */
365             if (curr.mPriority <= mMin.mPriority) mMin = curr;
366         }
367         return minElem;
368     }
369 
370     /**
371      * Decreases the key of the specified element to the new priority.  If the
372      * new priority is greater than the old priority, this function throws an
373      * IllegalArgumentException.  The new priority must be a finite double,
374      * so you cannot set the priority to be NaN, or +/- infinity.  Doing
375      * so also throws an IllegalArgumentException.
376      *
377      * It is assumed that the entry belongs in this heap.  For efficiency
378      * reasons, this is not checked at runtime.
379      *
380      * @param entry The element whose priority should be decreased.
381      * @param newPriority The new priority to associate with this entry.
382      * @throws IllegalArgumentException If the new priority exceeds the old
383      *         priority, or if the argument is not a finite double.
384      */
385     public void decreaseKey(Entry<T> entry, double newPriority) {
386         checkPriority(newPriority);
387         if (newPriority > entry.mPriority)
388             throw new IllegalArgumentException("New priority exceeds old.");
389 
390         /* Forward this to a helper function. */
391         decreaseKeyUnchecked(entry, newPriority);
392     }
393     
394     /**
395      * Deletes this Entry from the Fibonacci heap that contains it.
396      *
397      * It is assumed that the entry belongs in this heap.  For efficiency
398      * reasons, this is not checked at runtime.
399      *
400      * @param entry The entry to delete.
401      */
402     public void delete(Entry<T> entry) {
403         /* Use decreaseKey to drop the entry's key to -infinity.  This will
404          * guarantee that the node is cut and set to the global minimum.
405          */
406         decreaseKeyUnchecked(entry, Double.NEGATIVE_INFINITY);
407 
408         /* Call dequeueMin to remove it. */
409         dequeueMin();
410     }
411 
412     /**
413      * Utility function which, given a user-specified priority, checks whether
414      * it's a valid double and throws an IllegalArgumentException otherwise.
415      *
416      * @param priority The user's specified priority.
417      * @throws IllegalArgumentException If it is not valid.
418      */
419     private void checkPriority(double priority) {
420         if (Double.isNaN(priority))
421             throw new IllegalArgumentException(priority + " is invalid.");
422     }
423 
424     /**
425      * Utility function which, given two pointers into disjoint circularly-
426      * linked lists, merges the two lists together into one circularly-linked
427      * list in O(1) time.  Because the lists may be empty, the return value
428      * is the only pointer that's guaranteed to be to an element of the
429      * resulting list.
430      *
431      * This function assumes that one and two are the minimum elements of the
432      * lists they are in, and returns a pointer to whichever is smaller.  If
433      * this condition does not hold, the return value is some arbitrary pointer
434      * into the doubly-linked list.
435      *
436      * @param one A pointer into one of the two linked lists.
437      * @param two A pointer into the other of the two linked lists.
438      * @return A pointer to the smallest element of the resulting list.
439      */
440     private static <T> Entry<T> mergeLists(Entry<T> one, Entry<T> two) {
441         /* There are four cases depending on whether the lists are null or not.
442          * We consider each separately.
443          */
444         if (one == null && two == null) { // Both null, resulting list is null.
445             return null;
446         }
447         else if (one != null && two == null) { // Two is null, result is one.
448             return one;
449         }
450         else if (one == null && two != null) { // One is null, result is two.
451             return two;
452         }
453         else { // Both non-null; actually do the splice.
454             /* This is actually not as easy as it seems.  The idea is that we'll
455              * have two lists that look like this:
456              *
457              * +----+     +----+     +----+
458              * |    |--N->|one |--N->|    |
459              * |    |<-P--|    |<-P--|    |
460              * +----+     +----+     +----+
461              *
462              *
463              * +----+     +----+     +----+
464              * |    |--N->|two |--N->|    |
465              * |    |<-P--|    |<-P--|    |
466              * +----+     +----+     +----+
467              *
468              * And we want to relink everything to get
469              *
470              * +----+     +----+     +----+---+
471              * |    |--N->|one |     |    |   |
472              * |    |<-P--|    |     |    |<+ |
473              * +----+     +----+<-  +----+ | |
474              *                    P        | |
475              *                   N         N |
476              * +----+     +----+  ->+----+ | |
477              * |    |--N->|two |     |    | | |
478              * |    |<-P--|    |     |    | | P
479              * +----+     +----+     +----+ | |
480              *              ^ |             | |
481              *              | +-------------+ |
482              *              +-----------------+
483              *
484              */
485             Entry<T> oneNext = one.mNext; // Cache this since we're about to overwrite it.
486             one.mNext = two.mNext;
487             one.mNext.mPrev = one;
488             two.mNext = oneNext;
489             two.mNext.mPrev = two;
490 
491             /* Return a pointer to whichever's smaller. */
492             return one.mPriority < two.mPriority? one : two;
493         }
494     }
495 
496     /**
497      * Decreases the key of a node in the tree without doing any checking to ensure
498      * that the new priority is valid.
499      *
500      * @param entry The node whose key should be decreased.
501      * @param priority The node's new priority.
502      */
503     private void decreaseKeyUnchecked(Entry<T> entry, double priority) {
504         /* First, change the node's priority. */
505         entry.mPriority = priority;
506 
507         /* If the node no longer has a higher priority than its parent, cut it.
508          * Note that this also means that if we try to run a delete operation
509          * that decreases the key to -infinity, it's guaranteed to cut the node
510          * from its parent.
511          */
512         if (entry.mParent != null && entry.mPriority <= entry.mParent.mPriority)
513             cutNode(entry);
514 
515         /* If our new value is the new min, mark it as such.  Note that if we
516          * ended up decreasing the key in a way that ties the current minimum
517          * priority, this will change the min accordingly.
518          */
519         if (entry.mPriority <= mMin.mPriority)
520             mMin = entry;
521     }
522 
523     /**
524      * Cuts a node from its parent.  If the parent was already marked, recursively
525      * cuts that node from its parent as well.
526      *
527      * @param entry The node to cut from its parent.
528      */
529     private void cutNode(Entry<T> entry) {
530         /* Begin by clearing the node's mark, since we just cut it. */
531         entry.mIsMarked = false;
532 
533         /* Base case: If the node has no parent, we're done. */
534         if (entry.mParent == null) return;
535 
536         /* Rewire the node's siblings around it, if it has any siblings. */
537         if (entry.mNext != entry) { // Has siblings
538             entry.mNext.mPrev = entry.mPrev;
539             entry.mPrev.mNext = entry.mNext;
540         }
541 
542         /* If the node is the one identified by its parent as its child,
543          * we need to rewrite that pointer to point to some arbitrary other
544          * child.
545          */
546         if (entry.mParent.mChild == entry) {
547             /* If there are any other children, pick one of them arbitrarily. */
548             if (entry.mNext != entry) {
549                 entry.mParent.mChild = entry.mNext;
550             }
551             /* Otherwise, there aren't any children left and we should clear the
552              * pointer and drop the node's degree.
553              */
554             else {
555                 entry.mParent.mChild = null;
556             }
557         }
558 
559         /* Decrease the degree of the parent, since it just lost a child. */
560         --entry.mParent.mDegree;
561 
562         /* Splice this tree into the root list by converting it to a singleton
563          * and invoking the merge subroutine.
564          */
565         entry.mPrev = entry.mNext = entry;
566         mMin = mergeLists(mMin, entry);
567 
568         /* Mark the parent and recursively cut it if it's already been
569          * marked.
570          */
571         if (entry.mParent.mIsMarked)
572             cutNode(entry.mParent);
573         else
574             entry.mParent.mIsMarked = true;
575 
576         /* Clear the relocated node's parent; it's now a root. */
577         entry.mParent = null;
578     }
579 }
View Code
 1 /*****************************************************************************
 2  * File: DirectedGraph.java
 3  * Author: Keith Schwarz (htiek@cs.stanford.edu)
 4  *
 5  * A class representing a directed graph where each edge has an associated 
 6  * real-valued length.  Internally, the class is represented by an adjacency 
 7  * list.
 8  */
 9 import java.util.*; // For HashMap
10 
11 public final class DirectedGraph<T> implements Iterable<T> {
12     /* A map from nodes in the graph to sets of outgoing edges.  Each
13      * set of edges is represented by a map from edges to doubles.
14      */
15     private final Map<T, Map<T, Double>> mGraph = new HashMap<T, Map<T, Double>>();
16 
17     /**
18      * Adds a new node to the graph.  If the node already exists, this
19      * function is a no-op.
20      *
21      * @param node The node to add.
22      * @return Whether or not the node was added.
23      */
24     public boolean addNode(T node) {
25         /* If the node already exists, don't do anything. */
26         if (mGraph.containsKey(node))
27             return false;
28 
29         /* Otherwise, add the node with an empty set of outgoing edges. */
30         mGraph.put(node, new HashMap<T, Double>());
31         return true;
32     }
33 
34     /**
35      * Given a start node, destination, and length, adds an arc from the
36      * start node to the destination of the length.  If an arc already
37      * existed, the length is updated to the specified value.  If either
38      * endpoint does not exist in the graph, throws a NoSuchElementException.
39      *
40      * @param start The start node.
41      * @param dest The destination node.
42      * @param length The length of the edge.
43      * @throws NoSuchElementException If either the start or destination nodes
44      *                                do not exist.
45      */
46     public void addEdge(T start, T dest, double length) {
47         /* Confirm both endpoints exist. */
48         if (!mGraph.containsKey(start) || !mGraph.containsKey(dest))
49             throw new NoSuchElementException("Both nodes must be in the graph.");
50 
51         /* Add the edge. */
52         mGraph.get(start).put(dest, length);
53     }
54 
55     /**
56      * Removes the edge from start to dest from the graph.  If the edge does
57      * not exist, this operation is a no-op.  If either endpoint does not
58      * exist, this throws a NoSuchElementException.
59      *
60      * @param start The start node.
61      * @param dest The destination node.
62      * @throws NoSuchElementException If either node is not in the graph.
63      */
64     public void removeEdge(T start, T dest) {
65         /* Confirm both endpoints exist. */
66         if (!mGraph.containsKey(start) || !mGraph.containsKey(dest))
67             throw new NoSuchElementException("Both nodes must be in the graph.");
68 
69         mGraph.get(start).remove(dest);
70     }
71 
72     /**
73      * Given a node in the graph, returns an immutable view of the edges
74      * leaving that node, as a map from endpoints to costs.
75      *
76      * @param node The node whose edges should be queried.
77      * @return An immutable view of the edges leaving that node.
78      * @throws NoSuchElementException If the node does not exist.
79      */
80     public Map<T, Double> edgesFrom(T node) {
81         /* Check that the node exists. */
82         Map<T, Double> arcs = mGraph.get(node);
83         if (arcs == null)
84             throw new NoSuchElementException("Source node does not exist.");
85 
86         return Collections.unmodifiableMap(arcs);
87     }
88 
89     /**
90      * Returns an iterator that can traverse the nodes in the graph.
91      *
92      * @return An iterator that traverses the nodes in the graph.
93      */
94     public Iterator<T> iterator() {
95         return mGraph.keySet().iterator();
96     }
97 }
View Code
  1 /**************************************************************************
  2  * File: Dijkstra.java
  3  * Author: Keith Schwarz (htiek@cs.stanford.edu)
  4  *
  5  * An implementation of Dijkstra's single-source shortest path algorithm.
  6  * The algorithm takes as input a directed graph with non-negative edge
  7  * costs and a source node, then computes the shortest path from that node
  8  * to each other node in the graph.
  9  *
 10  * The algorithm works by maintaining a priority queue of nodes whose
 11  * priorities are the lengths of some path from the source node to the
 12  * node in question.  At each step, the algortihm dequeues a node from
 13  * this priority queue, records that node as being at the indicated
 14  * distance from the source, and then updates the priorities of all nodes
 15  * in the graph by considering all outgoing edges from the recently-
 16  * dequeued node to those nodes.
 17  *
 18  * In the course of this algorithm, the code makes up to |E| calls to
 19  * decrease-key on the heap (since in the worst case every edge from every
 20  * node will yield a shorter path to some node than before) and |V| calls
 21  * to dequeue-min (since each node is removed from the prioritiy queue
 22  * at most once).  Using a Fibonacci heap, this gives a very good runtime
 23  * guarantee of O(|E| + |V| lg |V|).
 24  *
 25  * This implementation relies on the existence of a FibonacciHeap class, also
 26  * from the Archive of Interesting Code.  You can find it online at
 27  *
 28  *         http://keithschwarz.com/interesting/code/?dir=fibonacci-heap
 29  */
 30 
 31 import java.util.*; // For HashMap
 32 
 33 public final class Dijkstra {
 34     /**
 35      * Given a directed, weighted graph G and a source node s, produces the
 36      * distances from s to each other node in the graph.  If any nodes in
 37      * the graph are unreachable from s, they will be reported at distance
 38      * +infinity.
 39      *
 40      * @param graph The graph upon which to run Dijkstra's algorithm.
 41      * @param source The source node in the graph.
 42      * @return A map from nodes in the graph to their distances from the source.
 43      */
 44     public static <T> Map<T, Double> shortestPaths(DirectedGraph<T> graph, T source) {
 45         /* Create a Fibonacci heap storing the distances of unvisited nodes
 46          * from the source node.
 47          */
 48         FibonacciHeap<T> pq = new FibonacciHeap<T>();
 49 
 50         /* The Fibonacci heap uses an internal representation that hands back
 51          * Entry objects for every stored element.  This map associates each
 52          * node in the graph with its corresponding Entry.
 53          */
 54         Map<T, FibonacciHeap.Entry<T>> entries = new HashMap<T, FibonacciHeap.Entry<T>>();
 55 
 56         /* Maintain a map from nodes to their distances.  Whenever we expand a
 57          * node for the first time, we'll put it in here.
 58          */
 59         Map<T, Double> result = new HashMap<T, Double>();
 60 
 61         /* Add each node to the Fibonacci heap at distance +infinity since
 62          * initially all nodes are unreachable.
 63          */
 64         for (T node: graph)
 65             entries.put(node, pq.enqueue(node, Double.POSITIVE_INFINITY));
 66 
 67         /* Update the source so that it's at distance 0.0 from itself; after
 68          * all, we can get there with a path of length zero!
 69          */
 70         pq.decreaseKey(entries.get(source), 0.0);
 71 
 72         /* Keep processing the queue until no nodes remain. */
 73         while (!pq.isEmpty()) {
 74             /* Grab the current node.  The algorithm guarantees that we now
 75              * have the shortest distance to it.
 76              */
 77             FibonacciHeap.Entry<T> curr = pq.dequeueMin();
 78 
 79             /* Store this in the result table. */
 80             result.put(curr.getValue(), curr.getPriority());
 81 
 82             /* Update the priorities of all of its edges. */
 83             for (Map.Entry<T, Double> arc : graph.edgesFrom(curr.getValue()).entrySet()) {
 84                 /* If we already know the shortest path from the source to
 85                  * this node, don't add the edge.
 86                  */
 87                 if (result.containsKey(arc.getKey())) continue;
 88 
 89                 /* Compute the cost of the path from the source to this node,
 90                  * which is the cost of this node plus the cost of this edge.
 91                  */
 92                 double pathCost = curr.getPriority() + arc.getValue();
 93 
 94                 /* If the length of the best-known path from the source to
 95                  * this node is longer than this potential path cost, update
 96                  * the cost of the shortest path.
 97                  */
 98                 FibonacciHeap.Entry<T> dest = entries.get(arc.getKey());
 99                 if (pathCost < dest.getPriority())
100                     pq.decreaseKey(dest, pathCost);
101             }
102         }
103 
104         /* Finally, report the distances we've found. */
105         return result;
106     }
107     
108     public static void main(String[] argv)
109     {
110         DirectedGraph dg = new DirectedGraph();
111         dg.addNode("A");
112         dg.addNode("B");
113         dg.addNode("C");
114         dg.addNode("D");
115         dg.addNode("E");
116         
117         dg.addEdge("A", "B", 1);
118         dg.addEdge("B", "C", 2);
119         dg.addEdge("A", "C", 4);
120         dg.addEdge("C", "D", 8);
121         dg.addEdge("D", "E", 16);
122         dg.addEdge("C", "E", 32);
123         dg.addEdge("E", "B", 64);
124         
125         Map<String, Double> map = shortestPaths(dg, "A");
126         for (Map.Entry<String, Double> entry : map.entrySet()) {
127             System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
128         }
129     }
130 }
View Code
原文地址:https://www.cnblogs.com/swu-luo/p/3751861.html