Dijkstra 算法

Dijkstra 算法

Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。
问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径)
1)算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度

  本算法的主要步骤:

  1.找出距离起始顶点距离最短的顶点,这里设为顶点nowVertice.

  2.遍历所有与顶点nowVertice相邻的顶点nextVertice.如果发现选择nowVertice到达nextVertice的路径后,nextVertice距离起始顶点的距离比当前的距离小.便更新新的距离.如下:

    if(currDist[nextVertice] > currDist[nowVertice] + weight) {            //weight为从nowVertice到nextVertice说需要的权重
                    currDist[nextVertice] = currDist[nowVertice] + weight;
     }

    currDist是一个全局数组,currDist[i]意思就是当前起始顶点到顶点i的距离.

  3.将nowVertice从图中删除.

  4.重复步骤1,直到所有的顶点都被删除完.

 补充,在实现的时候,上面说的删除并不是真的直接从图中把某一顶点删除,这里会使用一个集合来存储所有的顶点,对该集合中的顶点进行删除动作,集合如下.

List<Integer> toBeChecked = new LinkedList<>();

 这里使用一个名为Graph的类来封装查找最短路径的相关内容:

/**
 * 使用邻接矩阵实现图<p>
 * 深度优先遍历与广度优先遍历<p>
 * 求最短路径:<p>
 *      1. Dijkstra 算法 <p>
 *      2. Ford 算法 <p>
 *      3. 通用型的纠正标记算法<p>
 * Created by Henvealf on 16-5-22.
 */
public class Graph<T> {
    private int[][] racs;       //邻接矩阵
    private T[] verticeInfo;   //各个点所携带的信息.

    private int verticeNum;             //顶点的数目,
    private int[] visitedCount;         //记录访问
    private int[] currDist;             //最短路径算法中用来记录每个顶点距离起始顶点路径的长度.

    public Graph(int[][] racs, T[] verticeInfo){
        if(racs.length != racs[0].length){
            throw new IllegalArgumentException("racs is not a adjacency matrix!");
        }
        if(racs.length != verticeInfo.length ){
            throw new IllegalArgumentException ("Argument of 2 verticeInfo's length is error!");
        }
        this.racs = racs;
        this.verticeInfo = verticeInfo;
        verticeNum = racs.length;
        visitedCount = new int[verticeNum];
    }
    //..........       
}
复制代码

   这里是使用的邻接矩阵来表示图,想要使用其他表示方法,自行稍微修改一下便可.下面是实现方法的代码:

复制代码
 1 /**
 2      * 使用 Dijkstra算法寻找最短路径
 3      * @param first 路径开始的顶点
 4      * @return 返回最后的最短路径
 5      */
 6     public int[] dijkstraAlgorithm(int first){
 7         if(first < 0 || first >= verticeNum ){
 8             throw new IndexOutOfBoundsException ("should between 0 ~ " + (verticeNum -1));
 9         }
10         setNumberAsInfinitie();
11         currDist[first] = 0;
12         List<Integer> toBeChecked = new LinkedList<>();
13         for(int i = 0; i < verticeNum; i ++){
14             toBeChecked.add(i);
15         }
16         while(!toBeChecked.isEmpty()){
17             int nowVertice = findMinCurrDistVerticeAndRemoveFormList(toBeChecked);
18             for(int i = 0; i < verticeNum; i ++){
19                 int nextVertice = -1;                       //邻接节点
20                 int weight = Integer.MAX_VALUE;             //到达邻接节点的权重
21                 if(racs[nowVertice][i] != Integer.MAX_VALUE){   //得到邻接顶点
22                     if(toBeChecked.contains(i)){
23                         nextVertice = i;
24                         weight = racs[nowVertice][i];
25                     }
26                 }
27                 if(nextVertice == -1) {continue;}
28                 if(currDist[nextVertice] > currDist[nowVertice] + weight){
29                     currDist[nextVertice] = currDist[nowVertice] + weight;
30                 }
31             }
32 
33         }
34         for(int i = 0; i < currDist.length; i++){
35             System.out.println("现在顶点 " + verticeInfo[i].toString() + " 距离顶点 " + verticeInfo[first].toString()  + " 的最短距离为 " + currDist[i]);
36         }
37         return currDist;
38     }
39   /**
40      * 将currDist数组初始化为无穷大
41      */
42     private void setNumberAsInfinitie(){
43         currDist = new int[verticeNum];
44         for (int i = 0; i < verticeNum; i++){
45             currDist[i] = Integer.MAX_VALUE;
46         }
47     }
48 
49     /**
50      * 寻找出当前距离起始顶点路径最短的顶点,并将其从toBeCheck中删除
51      * @param list
52      * @return
53      */
54     private int findMinCurrDistVerticeAndRemoveFormList(List<Integer> list){
55         int num = list.get(0);
56         int dist = currDist[list.get(0)];
57         int listIndex = 0;
58         for(int i = 1; i < list.size(); i ++){
59             int index = list.get(i);
60             if(currDist[index] < dist) {
61                 dist = currDist[index];
62                 num = index;
63                 listIndex = i;
64             }
65         }
66         list.remove(listIndex);
67         return num;
68     }
复制代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值