Dijkstra算法讲解(单源最短路径问题求解)

无论是算法分析课程还是Java课程设计,都对有向图中的最短路径情有独钟,今天准备对单愿最短路径的解决方案进行一下详解,免得每一次用到都是从头再来2333

适用条件:

在有向图中,求一个顶点到其他顶点的最短路径

首先让我们先回顾一下,最简单的多源最短路径的求法:Floyd算法

实例讲解

这里呢我们通过这个例题对这个算法进行解析:(节选自《啊哈算法》)

题目中的关系如图所示:

《Dijkstra算法讲解(单源最短路径问题求解)》

这里呢,我们依旧使用二维数组来存储顶点之间边的关系

《Dijkstra算法讲解(单源最短路径问题求解)》

为了让最后单源路径最短的问题方便读取答案,创建一个1号顶点到其他顶点初始路程的数组dist

《Dijkstra算法讲解(单源最短路径问题求解)》

求解思路

1、首先从距离起点最近的点进行操作,因为起点1不可能通过其他顶点获得到达该最近点的最短路径。
2、那么我们找到了顶点2,和Floyd方法类似,这个时候我们开始经过顶点2对顶点1的其他边进行优化。
3、比较dist[3]与dist[2]+e[2][3]的大小关系,如果dist[3]较大,则进行更新,这就使得顶点1到3的最短路径变短。
4、接下来,再剩下的3,4,5和6号顶点中,继续寻找离1号起点最近的顶点,进行路径更新。
5、最终通过其他顶点的优化后的道德单源最短路径为:
《Dijkstra算法讲解(单源最短路径问题求解)》

总结算法:

1、通过book[i]是否为1判断点i是否已经是最短路径的顶点集合P中,否则在Q中。
2、在Q中选取一个离起点最近的顶点加入到集合P中,并考察所有的以点u为起点的边
3、重复第二步,直到Q为空

算法实现:

/* *C语言实现,最简 */
#include <stdio.h>
int main()
{
    int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
    int inf = 99999999;//用inf(infinity的缩写)存储一个我们认为的正无穷值
    //读入n和m,n表示顶点个数,m表示边的条数
    scanf("%d %d",&n,&m);
    //初始化
    for(i = 1;i <= n;i++) {
        for(j = 1;j <= n;j++){
            if(i == j) e[i][j] = 0;
            else e[i][j] = inf;
        }
    }
    //读入边
    for (int i = 0; i < m; i++)
    {
        scanf("%d %d %d",&t1,&t2,&t3);
        e[t1][t2] = t3;
    }
    //初始化dis数组
    for(i = 1;i <= n;i++) {
        dis[i] = e[1][i];
    }
    //book数组初始化
    for(i = 1;i <= n;i++)
        book[i] = 0;
    book[1] = 1;

    //Dijkstra算法核心语句
    for(i = 1;i <= n - 1;i++)
    {
        //找到离1号顶点最近的顶点
        min = inf;
        for(j = 1;j <= n;i++)
        {
            if(book[j] == 0 && dis[j] < min)
            {
                min = dis[j];
                u = j;
            }
        }
        book[u] = 1;
        for(v = 1;v <= n;v++)
        {
            if(e[u][v] < inf){
                if(dis[v] > dis[u] + e[u][v])
                    dis[v] = dis[u] + e[u][v];
            }
        }
    }
    //输出最终结果
    for(i = 1;i <= n;i++)
        prntf("%d ",dis[i]);
    getchar();
    getchar();
    return 0;
}
/* *Java实现,非最优化解 */
package com.stortest.path;
import java.util.ArrayList;
import java.util.Scanner;

public class Dijkstra {

    public long[] result;//定义全局变量存储到各点的最短路径

    public class Edge{
        public int a,b,c;
        Edge(int a,int b,int c){//声明构造函数
            this.a = a;
            this.b = b;
            this.c = c;
        }
    }

    public boolean get(int n, int s, Edge[] A) {
        ArrayList<Integer> list = new ArrayList<Integer>();//生成list列表
        //初始化
        result = new long[n];
        boolean[] used = new boolean[n];//存储访问状态
        int[] num = new int[n];
        for(int i = 0;i < n;i++) {
            result[i] = Integer.MAX_VALUE;
            used[i] = false;
        }
        result[s] = 0;     //第s个顶点到自身距离为0
        used[s] = true;    //表示第s个顶点进入数组队
        list.add(s);      //第s个顶点入队


        while(list.size() != 0) {
            int a = list.get(0);   //获取数组队中第一个元素
            list.remove(0);         //删除数组队中第一个元素
            for(int i = 0;i < A.length;i++) {
                //当list数组队的第一个元素等于边A[i]的起点时
                if(a == A[i].a && result[A[i].b] > result[A[i].a] + A[i].c) { 
                    //判断 起点到终点的最短路径 是否可以更新
                    result[A[i].b] = result[A[i].a] + A[i].c;
                    if(!used[A[i].b]) {//如果终点是第一次被遍历
                        list.add(A[i].b);
                        used[A[i].b] = true;   //表示边A[i]的终点b已进入数组队
                    }
                }
            }
           // used[a] = false; //顶点a出数组对
        }
        return true;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Dijkstra text = new Dijkstra();//创建对象
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int m = input.nextInt();
        Edge[] A = new Edge[m];//创建内部类对象数组,存储边的关系
        for(int i = 0;i < m;i++)
        {
            int a = input.nextInt() - 1;
            int b = input.nextInt() - 1;
            int c = input.nextInt();
            A[i] = text.new Edge(a,b,c);
        }//接收输入数据
        if(text.get(n,0,A)){//调用子函数,输出到最远点的结果
            System.out.println(text.result[text.result.length - 1]);
        }
}

}

改进:

该算法的时间复杂度为O(N2),对于边数M少于N2的稀疏图来说,可以使用邻接矩阵进行优化,可以使时间复杂度优化到(M+N)logN

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/weixin_31347831/article/details/72520615
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞