迪杰斯特拉 dijkstra 算法思想+Java实现

求单源最短路径的经典算法,算法基于这样一种思想:
1 将顶点集V分成 S(开始只包含源点, S包含的点都是已经计算出最短路径的点) 和 V-S 集合(V-S 包含那些未确定最短路径的点)

2. 从V-S中选取这样一个顶点w: 满足经过S集合中任意顶点 v到w 的路径最短, 即
满足( 源到v的路径 + v到w的路径) 最小的那个w. 其中v 属于S, w属于S-V。将w 加入S, 并从V-S中移除w.

3. 如此反复,直到V-S变空集为止。


归纳基点:
比如开始 S中只有原点s, 那我们从V-S中选取离s最近的点w, 则s直接到w的路径一定最短。因为如果存在另一个点w2, 使得 s->w2->w 的路径比s 直接到w短,那么s->w2 一定 小于s->w, 那么 w就不是离s最近的点,与我们选取的w离s最近这个先前条件矛盾。所以在最开始,选出来的那个点 w 一定确定了最短路径,即s->w 的边长。 w已经确定,将w加入S.

2. 此时S中有 v1,v2....vk 顶点,V-S中剩下 w1,w2.....Wn-k 顶点。我们此时当然选择离S集合最近的点w.

w必然满足 D[w]= Min(D[v]+D[v to w])    其中 D[x] 表示从原点到x的最短路径长。

这个w 此时一定取得了最短路径D[w], 因为如果有其他的路径,假设是 S集合某路径->Wi->w, 那么就应当去选取Wi 做为该点而不是w. 因为 S集合某路径长D[v] + D[v to Wi] < D[v]+D[v to w] 与 w满足的公式矛盾。

因此w必然是最小的。将w加入 S集合。



3. 实现框架+核心代码:

采用邻接表存储图


1 /*
2 * 邻接边
3 * */
4 public class Edge {
5     public Vertex dest;//目标顶点
6     public double cost;//代价
7    
8     public Edge(Vertex d,double c){
9          dest=d;
10          cost=c;
11      }
12 }
13

顶点类:
1 public class Vertex  implements Comparable<Vertex>{
2     public String name;//顶点名
3     public List<Edge> adj;//邻接表
4     public double dist;// 从原点到该点的最短路径长
5     public Vertex prev;//最短路径前一个节点
6     public int scratch;//算法需要
7     public boolean visited;
8     public Vertex(String nm){
9          name=nm;
10          adj=new ArrayList<Edge>();
11          reset();
12      }
13     public void reset(){
14          visited=false;
15          dist=Graph.INFINITY;
16          prev=null;
17          scratch=0;
18      }
19     @Override
20     public int compareTo(Vertex o) {
21         double c=o.dist;
22         return dist<c?-1:dist>c?1:0;
23      }
24 }
25





1 /*
2      * 迪杰斯特拉算法.
3      *
4      * 使用优先级队列来存储V-S集合,这样队首的元素就是要选取加入S的元素。
5      *
6      * 每加入S一个元素,就用它去更新可更新的V-S中的元素。
7      *
8      * */
9     public void dijkstraSlow(String startName){
10          PriorityQueue<Vertex> pq=new PriorityQueue<Vertex>();
11          Vertex start=vertexMap.get(startName);
12         if(start==null)
13             throw new IllegalArgumentException("Hey fk,start vertex is illegal!");
14          clearAll();
15         //pq.add(start);
16          start.dist=0;
17         //构造V-S集合,将顶点全部装入优先级队列(V-S集合).
18         //优先级队列的队首元素即离原点最近的,因为Vertex对象的比较器是
19         //根据Vertex对象到原点的距离来比较的。
20         //其实这里可以进一步优化的,由于开始选中加入S的必定是原点,
21         //且只有刚加入S的顶点的邻接顶点才有可能是新的加入S的顶点,
22         //所以开始只要把原点放入vertexMap即可,第一次将原点加入S,
23         //然后更新其邻接点到原点的距离.从中选出最小的来加入S。
24         //这里为了保持算法清晰,没有进行优化.
25         for(Vertex v:vertexMap.values())
26              pq.add(v);
27        
28        
29         int seenNum=0;
30         while(!pq.isEmpty()&&seenNum<vertexMap.size()){
31            
32              Vertex v=pq.remove();//第一次取的是原点,其余情况自然是到原点最近的点.
33            
34             if(v.scratch!=0)//如果v已经加入了S,则跳过
35                 continue;
36            
37              v.scratch=1;//设置标志位,标志已经加入了S集合.
38            
39              seenNum++;//已经确定了多少顶点。
40            
41             //利用新加入S的点来更新V-S集合:
42            
43             //因为要更新V-S集合中点到原点的路径距离,并从中选取距离最小的点,因此从S集合的点的邻接
44             //点中选取,因为如果不与S的点邻接,就暂时无法更新其距离。而没有更新(即减小路径长)的点不可能被选中.
45             for(Edge e:v.adj){
46                  Vertex w=e.dest;
47                 double v_to_w=e.cost;
48                
49                 if(w.dist>v.dist+v_to_w){
50                      w.dist=v.dist+v_to_w;//更新其D[w]值
51                      w.prev=v;
52                     //pq.add(w);//加入优先级队列以备选取.
53                    
54                     //利用优先级队列来排序,取出离原点最近的。
55                     //队首的元素满足D[w]=Min(D[v]+D[v to w]).
56                     //删掉旧值,更新队列,
57                      pq.remove(w);
58                      pq.add(w);
59                  }
60              }
61            
62            
63          }
64            
65      }
66

你可能感兴趣的:(java,C++,c,算法,C#)