首页 > 代码库 > 【转】Fibonacci 斐波纳契堆优化 Dijkstra 最短路径算法
【转】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 }
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 }
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= "http://www.mamicode.com/+ entry.getValue()); 128 } 129 } 130 }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。