一、背景
全文根据《算法-第四版》,Dijkstra(迪杰斯特拉)算法,一种单源最短路径算法。我们把问题抽象为2步:1.数据结构抽象 2.实现。 分别对应第二章、第三章。
二、算法分析
2.1 数据结构
顶点+边->图。注意:Dijkstra算法的限定:
- 1.边有权重,且非负
- 2.边有向
2.1.1 加权有向边
DirectedEdge,API抽象如下:
方法 | 描述 |
DirectedEdge(int v, int w, double weight) | 构造边 |
double weight() | 边的权重 |
int from() | 边的起点 |
int to() | 边的终点 |
2.1.2 加权有向图
EdgeWeightedDigraph,API抽象如下:
方法 | 描述 |
EdgeWeightedDigraph(In in) | 从输入流中构造图 |
int V() | 顶点总数 |
int E() | 边总数 |
void addEdge(DirectedEdge e) | 将边e添加到图中 |
Iterable<DirectedEdge> adj(int v) | 从顶点v指出的边(邻接表,一个哈希链表,key=顶点,value=顶点指出的边链表) |
Iterable<DirectedEdge> edges() | 图中全部边 |
2.1.3 最短路径
DijkstraSP, API抽象如下:
方法 | 描述 |
DijkstraSP(EdgeWeightedDigraph G, int s) | 构造最短路径树 |
double distTo(int v) | 顶点s->v的距离,初始化无穷大 |
boolean hasPathTo(int v) | 是否存在顶点s->v的路径 |
Iterable<DirectedEdge> pathTo(int v) | s->v的路径,不存在为null |
元素:
最短路径树中的边(DirectedEdge[] edgeTo):
edgeTo[v]代表树中连接v和父节点的边(最短路径最后一条边数组),每个顶点都有一条这样的边,就组成了最短路径树。
原点到达顶点的距离:由顶点索引的数组 double[] distTo:
distTo[v] 代表原点到达顶点v的最短距离。
索引最小优先级队列: IndexMinPQ<Double> pq:
int[] pq:索引二叉堆(元素=顶点v,对应keys[v]):数组从pq[0]代表原点其它顶点从pq[1]开始插入
Key[] keys:元素有序数组(按照pq值作为下标赋值)存储到顶点的最短距离
2.2 算法核心
计算最短路径,三步骤:
- 1.每次选取最小节顶点:如果选择?使用最小堆排序,每次取堆顶元素即可。
- 2.遍历从顶点的发出的全部边
- 3.放松操作
三、具体实现
3.1 构造
3.1.1 元素迭代器
因为有遍历需要,这里定义Bag<Item>类实现了Iterable<Item>迭代器接口,Item是元素。就是个简单的某个元素的迭代器基本实现。
1 package study.algorithm.base; 2 3 import java.util.Iterator; 4 import java.util.NoSuchElementException; 5 6 /** 7 * The { @code Bag} class represents a bag (or multiset) of 8 * generic items. It supports insertion and iterating over the 9 * items in arbitrary order. 10 * <p> 11 * This implementation uses a singly linked list with a static nested class Node. 12 * See { @link LinkedBag} for the version from the 13 * textbook that uses a non-static nested class. 14 * See { @link ResizingArrayBag} for a version that uses a resizing array. 15 * The <em>add</em>, <em>isEmpty</em>, and <em>size</em> operations 16 * take constant time. Iteration takes time proportional to the number of items. 17 * <p> 18 * For additional documentation, see <a href="https://algs4.cs.princeton.edu/13stacks">Section 1.3</a> of 19 * <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne. 20 * 21 * @author Robert Sedgewick 22 * @author Kevin Wayne 23 * 24 * @param <Item> the generic type of an item in this bag 25 */ 26 public class Bag<Item> implements Iterable<Item> { 27 /** 28 * 首节点 29 */ 30 private Node<Item> first; 31 /** 32 * 元素个数 33 */ 34 private int n; 35 36 /** 37 * 链接表 38 * @param <Item> 39 */ 40 private static class Node<Item> { 41 private Item item; 42 private Node<Item> next; 43 } 44 45 /** 46 * 初始化一个空包 47 */ 48 public Bag() { 49 first = null; 50 n = 0; 51 } 52 53 /** 54 * Returns true if this bag is empty. 55 * 56 * @return { @code true} if this bag is empty; 57 * { @code false} otherwise 58 */ 59 public boolean isEmpty() { 60 return first == null; 61 } 62 63 /** 64 * Returns the number of items in this bag. 65 * 66 * @return the number of items in this bag 67 */ 68 public int size() { 69 return n; 70 } 71 72 /** 73 * Adds the item to this bag. 74 * 75 * @param item the item to add to this bag 76 */ 77 public void add(Item item) { 78 // 保留老的首节点 79 Node<Item> oldfirst = first; 80 // 构造一个新首节点 81 first = new Node<Item>(); 82 // item为新首节点item 83 first.item = item; 84 // 新节点的next节点指向老的首节点 85 first.next = oldfirst; 86 n++; 87 } 88 89 90 /** 91 * Returns an iterator that iterates over the items in this bag in arbitrary order. 92 * 93 * @return an iterator that iterates over the items in this bag in arbitrary order 94 */ 95 @Override 96 public Iterator<Item> iterator() { 97 return new LinkedIterator(first); 98 } 99 100 /** 101 * 链接迭代器,不支持移除 102 */ 103 private class LinkedIterator implements Iterator<Item> { 104 private Node<Item> current; 105 106 public LinkedIterator(Node<Item> first) { 107 current = first; 108 } 109 110 @Override 111 public boolean hasNext() { return current != null; } 112 @Override 113 public void remove() { throw new UnsupportedOperationException(); } 114 115 @Override 116 public Item next() { 117 if (!hasNext()) { 118 throw new NoSuchElementException(); 119 } 120 Item item = current.item; 121 // 下一节点 122 current = current.next; 123 return item; 124 } 125 } 126 127 /** 128 * Unit tests the { @code Bag} data type. 129 * 130 * @param args the command-line arguments 131 */ 132 public static void main(String[] args) { 133 Bag<String> bag = new Bag<String>(); 134 while (!StdIn.isEmpty()) { 135 String item = StdIn.readString(); 136 bag.add(item); 137 } 138 139 StdOut.println("size of bag = " + bag.size()); 140 for (String s : bag) { 141 StdOut.println(s); 142 } 143 } 144 145 }
3.1.2 具体构造
1. 从输入流中初始化图,输入流格式(括号内为注释,实际文件中不存在):
8(顶点数)
15(边数)
4 5 0.35(边4->5 权重=0.35)
5 4 0.35
4 7 0.37
5 7 0.28
7 5 0.28
5 1 0.32
0 4 0.38
0 2 0.26
7 3 0.39
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0