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 }
View Code
 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 }
View Code
  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 }
View Code

 

你可能感兴趣的:(fibonacci)