码迷,mamicode.com
首页 > 编程语言 > 详细

JAVA实践Dijkstra算法求最短路径距离

时间:2016-07-21 13:05:09      阅读:365      评论:0      收藏:0      [点我收藏+]

标签:

前言

Dijkstra算法用于求指定顶点到其他顶点的最短距离,时间复杂度O(N^2),据说可以使用堆优化到O(log N),然而还不会。
其特点是(对我来说)非常容易求得路径,和对应的距离。
缺陷也是存在的,此算法不能处理负权边。即距离为负时,就挂了。
此文内容同样参考《啊哈,算法》

另外个人感觉代码可能有错,还望有心人指点。

功能实现

输入一个顶点

输出路径
输出与路径对应的距离
如果存在不可到达的顶点,则输出该顶点不可到达

中文版参考

技术分享
对应的二维数组

     {0, 1, 12, INF, INF, INF},
     {INF, 0, 9, 3, INF, INF},
     {INF, INF, 0, INF, 5, INF},
     {INF, INF, 4, 0, 13, 15},
     {INF, INF, INF, INF, 0, 4},
     {INF, INF, INF, INF, INF, 0}
/**
 * Dijkstra算法
 *
 * 指定一个顶点,求该顶点到各个顶点的最短路径
 * Step 1:
 *      选择一个顶点,如顶点1
 *      使用布尔数组记录mark[1] = true;
 *      表示已经最短
 * Step 2:
 *      遍历各个顶点到达顶点1的长度,不能到达的为无穷大,到自己本身的为0
 *      使用与顶点个数大小相同的一维数组dis存储所有距离,此时为估计距离
 *      估计距离dis数组存储的是[顶点1],到达其他顶点的距离
 *      记录距离顶点1最近(距离最短)的顶点,即dis中最小的数,但是不能为0
 *      此处2号顶点距离顶点1最近,所以选择到达顶点2,此时顶点2已确定距离顶点1最短
 *      dis: [0 1 12 inf inf inf]
 * Step 3:
 *      选择进入顶点2
 *      表示顶点2已经最短,使用布尔数组记录mark[2] = true;
 *      遍历各个顶点到达顶点2的长度,将其与dis中的估计距离比较,小于估计距离的更新之
 *      遍历后得出
 *
 *      顶点2到顶点4的距离是3
 *      顶点2到顶点3的距离是9
 *
 *      顶点1到顶点2的距离为1
 *      顶点2到顶点3的距离为9
 *      相加起来就是顶点1到顶点4的最短距离:10
 *      比原来的小,更新估计顶点3的距离
 *      dis: [0 1 10 inf inf inf]
 *
 *      顶点2到顶点4的距离为3
 *      顶点1到顶点2的距离为1
 *      相加起来就是顶点1到顶点4的最短距离:4
 *      比原来小,更新顶点4的估计距离
 *      dis: [0 1 10 4 inf inf]
 *
 *      找出距离顶点1最近的,又未确定最短的顶点
 *      即mark[n] = false,同时数值最小的。
 *      这里mark[1]、mark[2]都是true,排除之后,数值最小的是4,选择它
 * Step 4:
 *      选择进入顶点4
 *      表示顶点4已经最短,使用布尔数组记录mark[4] = true;
 *      遍历各个顶点到达顶点4的长度,将其与dis中的估计距离比较,小于估计距离的更新之
 *      遍历后得出
 *
 *      顶点4到顶点3的距离是4
 *      顶点4到顶点5的距离是13
 *      顶点4到顶点6的距离是15
 *
 *      顶点1到顶点4的距离是4
 *      将距离相加,得到
 *      dis: [0 1 8 4 17 19]
 *      排除顶点1、2、4找最近的顶点,就是顶点3
 * Step n:
 *      重复选择距离最近的顶点
 *      进入,并标记已最短
 *      寻找新的距离,并更新估计距离
 *      排除已确定顶点,再次寻找最小数值顶点
 */

代码实现

public class DijkstraDemo {
    static int INF = 99;
    static int[][] arr = new int[][] {
            {0, 1, 12, INF, INF, INF},
            {INF, 0, 9, 3, INF, INF},
            {INF, INF, 0, INF, 5, INF},
            {INF, INF, 4, 0, 13, 15},
            {INF, INF, INF, INF, 0, 4},
            {INF, INF, INF, INF, INF, 0}
    };
    public static void main(String[] args) {
        int point = 1;
        System.out.println("起点为" + point);
        dijkstra(point);

        System.out.println();

        point = 2;
        System.out.println("起点为" + point);
        dijkstra(point);

    }
    public static void dijkstra(int point) {
        //顶点-1对应角标位置
        point--;

        //顶点个数
        int n = arr.length;

        //用于标记已经确定为最短距离的顶点
        boolean[] mark = new boolean[n];

        //存储最短距离时其在数组中的位置
        int nextMin = point;

        //用于记录找到的最短距离
        int nextMinDis;

        //当前进入的顶点在数组中的位置
        int curMin = point;

        //如果该不可到达,不应该记录
        boolean flag = true;

        //存储估计距离
        int[] dis = new int[n];

        //初始化估计距离
        initArray(dis, point);

        //记录遍历次数
        int count = 0;

        //记录路径
        int[] path = new int[n];
        int tail = 0;

        while (true) {
            //当前被选择的顶点,标记为真
            mark[curMin] = true;
            nextMinDis = INF;

            //每选择一次,自增
            count++;

            //如果flag为假,则存在不可到达的顶点,不必将其存储为路径之一
            if (flag) {
                path[tail++] = curMin + 1;
                flag = false;
            }

            //选择的顶点个数已经是所有顶点,可以写成for循坏的,i<n即可
            if (count == n) {
                break;
            }
            //System.out.println("--------------------------------------");
            for (int i = 0; i < n; i++) {

                //比较顶点i的估计距离 与前一个最短距离顶点到顶点i的距离
                //取较小者
                if (dis[i] > dis[curMin] + arr[curMin][i]) {
                    dis[i] = dis[curMin] + arr[curMin][i];
                    flag = true;
                    System.out.println("顶点" + (curMin+1) + "到达顶点" + (i+1) + ",距离" + dis[i]);
                }

                //获取更新后距离顶点1最短且尚未确定的顶点
                if (!mark[i] && dis[i] < nextMinDis) {
                    nextMinDis = dis[i];
                    nextMin = i;
                    flag = true;
                }
            }
            //System.out.println("--------------------------------------");
            curMin = nextMin;
        }


        System.out.println("最短路径与距离:");
        for (int i = 0; i < tail; i++) {
            System.out.print(path[i]);
            if (i != tail - 1) {
                System.out.print("→");
            }
        }
        System.out.println();
        for (int i = 0; i < tail; i++) {
            System.out.print(dis[path[i] - 1]);
            if (i != tail - 1) {
                System.out.print("--");
            }
        }
        System.out.println();
        for (int i = 0; i < n; i++) {
            if (!mark[i]) {
                System.out.println("顶点" + (i+1) + "不可到达");
            }
        }
    }

    public static void initArray(int[] dis, int point) {
        // 初始化估计距离,指定起点距离为0
        // 其他未确定的都是,距离该顶点的距离
        dis[point] = 0;
        for (int i = 0; i < dis.length; i++) {
            if (i != point) {
                dis[i] = arr[point][i];
                //System.out.println(dis[i] + " i=" + i);
            }
        }
    }
}

结果

技术分享

起点为1
顶点2到达顶点3,距离10
顶点2到达顶点4,距离4
顶点4到达顶点3,距离8
顶点4到达顶点5,距离17
顶点4到达顶点6,距离19
顶点3到达顶点5,距离13
顶点5到达顶点6,距离17
最短路径与距离:
1→2→4→3→5→6
0--1--4--8--13--17

起点为2
顶点4到达顶点3,距离7
顶点4到达顶点5,距离16
顶点4到达顶点6,距离18
顶点3到达顶点5,距离12
顶点5到达顶点6,距离16
最短路径与距离:
2→4→3→5→6
0--3--7--12--16
顶点1不可到达

结束语

寻找最短路径的应用还是不少的,做这个给我一种在做地图导航的感觉。成就Max。。。

每次写出中文思路,可以找出思维漏洞,写代码卡壳了就回去看思路,再写,很不错的一种方式。

当然这种思路只有自己能看懂了(逃

END

JAVA实践Dijkstra算法求最短路径距离

标签:

原文地址:http://blog.csdn.net/xubaifu1997/article/details/51980704

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!