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

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

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

  1 /***********************************************************************
2 * File: FibonacciHeap.java
3 * Author: Keith Schwarz ([email protected])
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 ([email protected])
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 }

 1 /*****************************************************************************
2 * File: DirectedGraph.java
3 * Author: Keith Schwarz ([email protected])
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 }

  1 /**************************************************************************
2 * File: Dijkstra.java
3 * Author: Keith Schwarz ([email protected])
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 }

时间: 2024-10-22 02:09:37

【转】Fibonacci 斐波纳契堆优化 Dijkstra 最短路径算法的相关文章

斐波那契堆

斐波纳契堆(Fibonacci Heap)于 1984 年由 Michael L. Fredman 与 Robert E. Tarjan 提出,1987 年公开发表,名字来源于运行时分析所使用的斐波那契数. 斐波那契堆同二项堆(Binomial Heap)一样,也是一种可合并堆(Mergeable Heap).与二项堆一样,斐波那契堆是由一组最小堆有序树构成,但堆中的树并不一定是二项树.与二项堆中树都是有序的不同,斐波那契堆中的树都是有根而无序的. 实际上,斐波那契堆松散地基于二项堆.如果不对斐

《Thinking in Algorithm》16.堆结构之斐波那契堆

堆的变体: 二叉堆 二项堆 斐波那契堆 前面的博客中我们讲到的堆的两种变体,二叉堆和二项堆,今天我们要讲的就是著名的斐波那契堆. 依然首先列出了三种堆的时间复杂的比较. 从上面能发现斐波那契堆的时间复杂度在很多操作上有优化,如insert, minimum, union , decrease-key,而extreact-min,delete没有变化. 可能看到这很多人会说为什么有这么好的斐波那契堆,我们还要去研究其他堆呢,确实,理论上来讲,对于extreact-min和delete操作想对于其他

斐波纳契数列

查找斐波纳契数列中第 N 个数. 所谓的斐波纳契数列是指: 前2个数是 0 和 1 . 第 i 个数是第 i-1 个数和第i-2 个数的和. 斐波纳契数列的前10个数字是: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ... 样例 给定 1,返回 0 给定 2,返回 1 给定 10,返回 34 虽然这道题是一道入门级的题目,可是在第一遍做的时候并没有多想,直接使用的递归,然后数据通过95%,显示的到47的时候就溢出了.经过学习前辈的经验,该题的收获如下: 方法1:使用递归解,

HDU 2516 取石子游戏 斐波纳契博弈

斐波纳契博弈: 有一堆个数为n的石子,游戏双方轮流取石子,满足: 1)先手不能在第一次把所有的石子取完: 2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍). 约定取走最后一个石子的人为赢家,求必败态. 证明 FBI数为必败局: 1.对于任意一个FBI数 FBI[K]=FBI[K-1]+FBI[K-2],我们可以将FBI[K]看成石子数目分别是FBI[K-1],FBI[K-2]的两堆(一定可以这样分,因为FBI[K-1] > FBI[K-2]*2,若先

[CLRS][CH 19]斐波那契堆

斐波那契堆简介 斐波那契堆(Fibnacci Heap)有两种用途:第一,支持一系列操作,这些操作构成了所谓的可合并堆.第二,其一些操作可以在常数时间内完成,这使得这种数据结构非常适合于需要频繁调用这些操作的应用. 可合并堆(Mergeable Heap)支持如下五种操作:Make-Heap(), Insert(H, x), Minmun(H), Extract-Min(H), Union(H1, H2).事实上,就是具备了快速合并操作的堆(Heap). 斐波那契堆还支持额外两种操作:Decre

笔试算法题(46):简介 - 二叉堆 &amp; 二项树 &amp; 二项堆 &amp; 斐波那契堆

二叉堆(Binary Heap) 二叉堆是完全二叉树(或者近似完全二叉树):其满足堆的特性:父节点的值>=(<=)任何一个子节点的键值,并且每个左子树或者右子树都是一 个二叉堆(最小堆或者最大堆):一般使用数组构建二叉堆,对于array[i]而言,其左子节点为array[2*i],其右子节点为 array[2*i+1]:二叉堆支持插入,删除,查找最大(最小)键值的操作,但是合并二叉堆的复杂度较高,时间复杂度为O(N):但是二项堆或者斐波 那契堆则仅需要O(logN): 二项树(Binomial

用PHP迭代器来实现一个斐波纳契数列

斐波纳契数列通常做法是用递归实现,当然还有其它的方法.这里现学现卖,用PHP的迭代器来实现一个斐波纳契数列,几乎没有什么难度,只是把类里的next()方法重写了一次.注释已经写到代码中,也是相当好理解的. <?php /* *@author [email protected] */ class Fibonacci implements Iterator { private $previous = 1; private $current = 0; private $key = 0; public

优先队列——斐波那契堆

1. 引言 最近一直在写最短路径的迪杰斯特拉与双向迪杰斯特拉算法,使用优先队列可以极大的加快算法的运行效率.比如在OL数据集中,对于迪杰斯特拉算法用优先队列(二叉堆实现)代替普通的数组(数据结构书中提供的算法)快了将近60倍. 由上可得如何实现优先队列对迪杰斯特拉.双向迪杰斯特拉以及其它用到优先队列的最短路径求解算法(如reach.A*)等至关重要.另外对于一些其他用到优先队列的问题也具有相当的影响. 对于优先队列来说,只需要入队.出队即可,因为该文章只关注堆的插入(push)与删除(delet

golang 实现斐波那契堆

二叉堆提供了o(lgn) 时间的插入, 删除最小,降级等操作,o(n) 时间的合并操作;  斐波那契堆提供了更优操作时间界限:o(1) 插入, o(lgn) 删除最小, o(lgn) 删除, o(1)合并. 根据算法导论上说,斐波那契堆在删除最小或删除操作被执行次数相比其他操作少得多时,尤为适用.一些图的算法中(计算最小生成树,单源最短路径)作为基本构建块(作为优先队用). 考虑到斐波那契堆实现的复杂,可能二叉堆在实践上更具可用性.就像rob pike 在 <notes on programmi