迪杰斯特拉 订阅
艾兹格·W·迪科斯彻 (Edsger Wybe Dijkstra,1930年5月11日~2002年8月6日)荷兰人。 计算机科学家,毕业就职于荷兰Leiden大学,早年钻研物理及数学,而后转为计算学。曾在1972年获得过素有计算机科学界的诺贝尔奖之称的图灵奖,之后,他还获得过1974年 AFIPS Harry Goode Memorial Award、1989年ACM SIGCSE计算机科学教育教学杰出贡献奖、以及2002年ACM PODC最具影响力论文奖。 展开全文
艾兹格·W·迪科斯彻 (Edsger Wybe Dijkstra,1930年5月11日~2002年8月6日)荷兰人。 计算机科学家,毕业就职于荷兰Leiden大学,早年钻研物理及数学,而后转为计算学。曾在1972年获得过素有计算机科学界的诺贝尔奖之称的图灵奖,之后,他还获得过1974年 AFIPS Harry Goode Memorial Award、1989年ACM SIGCSE计算机科学教育教学杰出贡献奖、以及2002年ACM PODC最具影响力论文奖。
信息
主要成就
1972年获得图灵奖 1989年计算机科学教育杰出贡献奖 2002年ACM PODC最具影响力论文奖
毕业院校
荷兰Leiden大学
国    籍
荷兰
出生地
荷兰鹿特丹(Rotterdam)
别    名
艾兹格·迪科斯特拉
中文名
艾兹格·迪科斯彻
外文名
Edsger Wybe Dijkstra
出生日期
1930年5月11日
逝世日期
2002年8月6日
职    业
计算机科学家
艾兹格·迪科斯彻成就
艾兹格·W·迪科斯彻(Edsger Wybe Dijkstra)1 提出“goto有害论”;2 提出信号量和PV原语;3 解决了“哲学家聚餐”问题;4 Dijkstra最短路径算法和银行家算法的创造者;5 第一个Algol 60编译器的设计者和实现者;6 THE操作系统的设计者和开发者;与D. E. Knuth并称为我们这个时代最伟大的计算机科学家的人。与癌症抗争多年,于2002年8月6日在荷兰Nuenen自己的家中去世,享年72岁。
收起全文
精华内容
下载资源
问答
  • 迪杰斯特拉
    千次阅读
    2022-03-21 20:23:03

    一.基本概念

    迪杰斯特拉算法是一种计算图论单源路径最短的算法,算法核心思想是贪心,即保证每一个【被保存的路径】都是通过【前一个路径】得出的,每条路径都是最短的,得出的路径必然是最短的,详细原理证明可以去CSDN社区自行搜索,本文章主要是对迪杰斯特拉算法的一个基本解释和算法实现。

    普里姆算法和迪杰斯特拉的算法的差别在哪里呢。笔者认为:

    两者都是求“权值”最小,但他们所处的环境不一样,首先谈谈他们的应用场景,迪杰斯特拉能用于有向图,但普里姆算法只能应用于无向图,如果用了有向图,我们不能保证【权值最小】的边来源于我们所选择的边,也就是说:普里姆算法更注重于一条路从头走到尾的消耗,中间的路径怎么样,都无所谓,因为我们选择的边必须全部走完,而迪杰斯特拉算法注重于,每条单元路径都是最短最优的,使得整棵树都是最优的

    所以迪杰斯特拉一般用于解决单源最短路径问题。

    二.算法思想

    迪杰斯特拉的思想在于决策层的建立(这个并不是名词,是笔者为了便于理解所提出的),只有一层决策层,这一层包含了所有顶点,每进行一次【顶点选择】都要更新一次【决策层】

    算法的核心部分有一个是:当我们找到了当前层的一个最短路径,那么我们就将这个最短路径所对应顶点加入,然后后续决策的时候,该顶点的决策层值不变,有人就要问了?为啥这层找到了,后面就不找了,不能走其他顶点然后再绕回来这个顶点吗,也许权值更小呢?

    这就体现出迪杰斯特拉和普里姆算法的区别了,笔者在普里姆算法实现中就提到普里姆的决策层的“由谁决策出来的”是可以变化的,但这里是不可以变化的,为什么?因为权值大于0,其他顶点必定大于这个“最短路径顶点权值”,你现在都已经比这个权值大了,后续无论怎么加都会比当前这个决策要更大的,所以我们每次找到一个最短路径,马上废弃掉,进行保存

    我们找到一条最短路的操作可以执行很多次,不断的找边,定边,直到所有边都被定好是最短路径了,那么迪杰斯特拉算法也就结束了。

    迪杰斯特拉在数据结构中一直为大学学生所害怕,毕竟图论的算法确确实实都很抽象也都挺麻烦的

    那么本篇文章将从代码实现方面一步一步指导读者手写出迪杰斯特拉算法。

    三.代码实现

    (1.)操作步骤

    要实现一个算法,我们不止要写完这次就结束了,我们更应该尝试的去理解他的底层原理(迪杰斯特拉算法的原理证明确实是非常难以理解的,所以我们只需要按部就班,学会了怎么写就行了,因为贪心算法很多时候都是突发奇想,需要严谨的数学证明,但如果举不出反例,那就是对的),然后分析他的代码实现步骤,和伪代码变成真正的代码。

    实现步骤如下:

    1.将起点的边权关系加入【决策层】数组

    2.选择【决策层数组】中权值最小的一条边的另一端称【新节点】,然后看看新节点的加入是否能使得原来【不能走通的路】和【走的路权值比现在费劲】的路变最优,更新完以后,将被更新的点设置成当前的【主动更新这个点的点】作为他的最后的路径,由于这个【新节点】已经找到了最短路径,那么标记为【不可访问】

    3.循环(2.)的决策,直到所有的边都被决策了(解释:由于每次我们都至少选择一条最短的边,所以我们一定会选择【图的边数】次,这里直接进行for循环,不必担心选不到)

    4.结束,输出。

    (2.)伪代码

    这里实际实现笔者先不给出,我们先分析我们需要什么,根据我们的操作步骤,我们需要

    1.决策层数组 int Distance[] //也叫最短路径数组,记录了每个点的最短路径

    2.标记数组 bool Done //如果某个顶点已经找到了路径了,我们需要标记,防止重复选择

    3.路径数组 int path[]//路径数组,只需要保存某个数组被找到最短路径前【是谁更新的他】的顶点即可,为什么只需要保存最后一次的呢,因为前一个顶点也是由前前一个顶点的最优路径走出来的,换言之,你只需要最后一个前顶点,顺着他逆推就可以找到全部的路径了!

    4.邻接矩阵 edge[][]//这里由于对边的请求较多,直接使用邻接矩阵,方便查询

    代码的步骤

    1.初始化邻接矩阵 //初始化操作笔者不作多讲,既然有兴趣实现不可能初始化不出来

    2.加入起点中的边权到决策层数组

    3.循环决策

    故,伪代码可以写成

    void ShortestPath(Graph& g)
    {
       决策层数组
       路径数组
        访问数组
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                初始化决策层
            }
        }
        访问数组[起点]=true//起点已经被访问了
        Distance[起点]=0//起点到自己的点是0
        path[起点]=-1//用于后面输出时候的标记,遇到-1停止输出路径
        for(int i=0;i<n;i++)
        {
            for(xxx)找权值最小的边
            Done[],path[],mineid//标记一下已经被访问了,标记一下路径,标记一下他的下标,后面更新用
            for(xxx)更新决策层
        }
        Show();//输出矩阵
    
    }

    (FINALL)真代码实现

    我们写好了伪代码以后,一个一个对着实现

    class Graph
    {
    public:
        int vernum;
        int edgenum;
        int edge[10][10];
        string ver[10];
        void init();
        int Locate(string s);
    };
    
    int Graph::Locate(string s)
    {
        for (int i = 0;i < vernum;i++)
        {
            if (ver[i] == s)return i;
        }
        return -1;
    }
    void Graph::init()
    {
        cout << "请输入:顶点个数 边数" << endl;
        cin >> this->vernum >> this->edgenum;
        cout << "初始化完成,请输入顶点信息" << endl;
        for (int i = 0;i < this->vernum;i++)
        {
            cin >> this->ver[i];
        }
        cout << "初始化完毕,下面开始初始化边" << endl;
        cout << "=============================" << endl;
        
        for (int i = 0;i < vernum;i++)
        {
            for (int j = 0;j < vernum;j++)
            {
                if (i == j)edge[i][j] = 0;
                else
                {
                    edge[i][j] = INT_MAX;
                }
            }
        }
        for (int i = 0;i < edgenum;i++)
        {
            string start, end;
            cin >> start >> end ;
            int s = Locate(start);
            int e = Locate(end);
            cin >> edge[s][e];
        }
        return;
    }
    #include <stack>;
    void Show(int distance[], int path[],Graph& g,int start)
    {
        for (int i = 0;i < g.vernum;i++)
        {   
            if (i != start&&distance[i]<INT_MAX)
            {
                cout << g.ver[start] << "到达" << g.ver[i] << "最短路径为" << distance[i]<<" 路径:";
                stack<int>s;
                int pre = path[i];
                s.push(i);
                while (pre != -1)
                {
                    s.push(pre);
                    pre = path[pre];
                }
                while (!s.empty())
                {
                    cout << g.ver[s.top()];
                    if (s.size() > 1)cout << "-->";
                    s.pop();
                }
                
                cout << endl;
            }
            else if (distance[i] = INT_MAX)
            {
                cout << g.ver[start] << "无法到达" << g.ver[i] << "! "<<endl;
            }
        }
        return;
    }
    
    void Dijkstra(string point, Graph g)
    {  
        cout << "迪杰斯特拉的算法如下:" << endl;
        int start = g.Locate(point);
        bool Done[100];
        int Distance[100];
        int path[100];
        for (int i = 0;i < g.vernum;i++)
        {
            Done[i] = false;
            Distance[i] = g.edge[start][i];
            if (Distance[i] < INT_MAX)
            {
                path[i] = start;
    
            }
            else
            {
                path[i] = -1;
            }
        }
        Done[start] = true;
        Distance[start] = 0;
        path[start] = -1;
        for (int i = 0;i < g.vernum;i++)//找最值,更新最值带来的影响
        {
            int minval = INT_MAX, u = start;
            for (int j = 0;j < g.vernum;j++)
            {
                if (!Done[j] && Distance[j] < minval)
                {
                    minval = Distance[j];
                    u = j;//找最值
                }
            }
            Done[u] = true;
            for (int k = 0;k < g.vernum;k++)
            {
                if (!Done[k] && g.edge[u][k] < INT_MAX && Distance[u] + g.edge[u][k] < Distance[k])//找影响
                {
                    Distance[k] = Distance[u] + g.edge[u][k];
                    path[k] = u;
                }
            }
        }
        Show(Distance, path,g,start);
    }
    

    (代码很长,请耐心观看)

    这里有个小BUG需要提醒一下,因为书上可能没有注意到

    就是更新路径的时候经常判断 某一点的权>当前点的到这点的路径权值+当前点的最短路径

    来看看是不是能更新,但如果后者是INT_MAX最大值,如果权值很大的情况下

    极有可能溢出

    可以将等式换成 某一点的权减去当前点到这点的路径权是否大于当前点的当前路径

    这个等式在弗洛伊德算法中笔者会提到

    输出矩阵写一个Show函数,使用栈进行递归操作即可

    成果展示

     参照了B站王卓老师的测试样例,结果一致

    再谈迪杰斯特拉算法:

    迪杰斯特拉算法对大众考研学子和数据结构及算法爱好者都是入门的一个算法,如果读者害怕自己学不会学不好,无法理解,那就多看几遍,笔者也是从只会写链表到手写迪杰斯特拉算法的,没有谁学数据结构是一路通窍的,笔者学KMP曾半个月走不出next数组的坑里,最后也大彻大悟了

    另外笔者分享一下在写算法类题目时的感想:

    其实迪杰斯特拉算法和DFS,BFS的本质差不多,都是通过“搜索”来完成对某路径的查找,但其实DFS,BFS一样也能通过设定回溯数组或者其他操作来找到最短路,但显然DFS,BFS是暴力搜索,每一步的探索都是没有目的的盲目搜索,和迪杰斯特拉的贪心搜索效率差很多,但笔者认为:当任意一个顶点,他都能向上下左右走通,并且边权为0,1的时候,迪杰斯特拉其实跟DFS,BFS差不多,因为迪杰斯特拉需要通过边权关系来模拟贪心来达到最快最优解,而此时边权意义不大的时候,迪杰斯特拉也就失去了他的优势,但很显然我们大部分的应用还是有边权的,读者可以根据自己的题目情况,来确认使用深广搜还是迪杰斯特拉,不过目前算法题(LEETCODE为主)中很少见直接使用迪杰斯特拉算法的

    最后感谢您的阅读。

    文章为笔者笔记,如果文章有错误之处,描述不当之处还请您告知。

    希望这篇文章能给您带来一些收获

    更多相关内容
  • Dijkstra算法 Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,是广度优先算法的一种,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。其基本原理是:...
  • 总结最短路径算法关键先把已知最短路径顶点集...集中在加入时可以记录每个顶点的最短路径也可以在加入完毕 后回溯找到每个顶点的最短路径和权重 迪杰斯特拉算法用于求解一个有向图也 可以是无向图无向图是有向图的一种
  • def Dijkstra(network,s,d):#迪杰斯特拉算法算s-d的最短路径,并返回该路径和代价 print(Start Dijstra Path……) path=[]#s-d的最短路径 n=len(network)#邻接矩阵维度,即节点个数 fmax=999 w=[[0 for i in ...
  • C++版本迪杰斯特拉(Dijkstra)算法原理及代码实现
  • 介绍学校的主要地点和这些地点的特点,以及从一个地点到达另外一个地点的最短路径。
  • 迪杰斯特拉算法实现;迪杰斯特拉--算法思想; 设给定源点为VsS为已求得最短路径的终点集开始时令S={Vs} 当求得第一条最短路径(Vs Vi)后S为{VsVi} 根据以下结论可求下一条最短路径 设下一条最短路径终点为Vj 则Vj只有 ...
  • matlab编写迪杰斯特拉算法求解求最短路问题,文件是程序源代码
  • 用于求解路径规划算法,Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的...
  • 数据结构与算法中图求最短路径,迪杰斯特拉算法的实现,带详细注释,可完整实现。
  • 由于AOE网中的某些活动能够同时进行,故完成整个工程所必须花费的时间应该为始点到终点的最大路径长度。关键路径长度是整个工程所需的最短工期。
  • 迪杰斯特拉派.rar,迪杰斯特拉派,迪杰斯特拉派_流量预测.docx,train.csv,test.csv
  • 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外...
  • 一、 迪杰斯特拉算法思想 Dijkstra算法主要针对的是有向图的单元最短路径问题,且不能出现权值为负的情况!Dijkstra算法类似于贪心算法,其应用根本在于最短路径的最优子结构性质。 最短路径的最优子结构性质: ...
  • 迪杰斯特拉算法

    2018-04-06 13:42:34
    迪杰斯特拉算法,迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以...
  • 用MATLAB实现迪杰斯特拉算法来寻找最短路径,压缩包中DIJ为算法的执行程序,SymMatrix为将邻接矩阵补齐为对称矩阵的程序,两个graph文件存储的两个邻接矩阵,DIJ加载了其中一个进行计算。也可以自己重新编辑邻接矩阵...
  • 2020中兴捧月算法大赛迪杰斯特拉赛道初赛题解源码,50个字的限制真的好傻啊
  • 迪杰斯特拉dijkstra算法 用邻接矩阵GA来表示带权有向图s为已找到从v出发的最短路径的终点的集合它的初始状态为空集那么从v出发到图上其余各顶点可能达到的最短路径长度的初值为dist[i]=cost[v0,vi](viV) 选择vj使得...
  • 这个ZIP包含了最短路径算法中两个经典的算法(迪杰斯特拉和弗洛伊德),这个是我在大一的时候写的程序设计课程的作业之一。有需要的小伙伴可以下载学习。
  • 迪杰斯特拉 C++

    2018-05-29 23:12:50
    C++的迪杰斯特拉算法C++的迪杰斯特拉算法C++的迪杰斯特拉算法
  • 一步步带你用Python实现迪杰斯特拉算法

    基本概述

    • 应用场景:
      在这里插入图片描述
      (1)分析一下,虽然还是求最短路径,但是是到各个点的最短路径,假如从G点出发,除了能直接到达的:A、B、E、F,如果要到达D点就有两种选择:一是GBD,二是GFD,选择出一条最短路径

    • 迪杰斯特拉算法介绍:
      在这里插入图片描述

    • 迪杰斯特拉算法过程:

    在这里插入图片描述
    在这里插入图片描述

    图解

    在这里插入图片描述

    Python实现

    # 迪杰斯特拉算法
    
    class VisitedVertex(object):
        def __init__(self, length: int, index: int):
            """
            :param length: 表示顶点的个数
            :param index: 出发顶点对应的下标,比如G顶点,下标就是6
            """
            self.index = index  # 传入的顶点序号,打印时需要用到
            self.ver = None  # 为了便于打印顶点封装一个对象
            
            # 记录各个顶点是否访问过 1表示访问过,0表示未访问过,会动态更新
            self.already_array = [0] * length
            # 每个下标对应的值为前一个顶点的下标,会动态更新
            self.pre_visited = [0] * length
            # 记录出发顶点到其他所有顶点的距离,比如G为出发点,就记录G到其他顶点的距离,会动态更新,求的最短距离会存放在dis
            # 初始化 dis数组
            self.dis = [float('inf')] * length
            # 设置出发顶点被访问过为1
            self.already_array[index] = 1
            # 设置出发顶点的访问距离为0
            self.dis[index] = 0
    
        def is_visited(self, index: int):
            """
            判断index顶点是否被访问过
            :param index: 传入的顶点
            :return: 如果访问过,就返回True,否则返回False
            """
            return self.already_array[index] == 1
    
        def update_dis(self, index: int, length: int):
            """
            更新出发顶点到index顶点的距离
            :param index: 传入的index
            :param length: 传入的length
            :return:
            """
            self.dis[index] = length
    
        def update_pre(self, pre: int, index: int):
            """
            更新顶点的前驱为index结点
            :param pre:
            :param index:
            :return:
            """
            self.pre_visited[pre] = index
    
        def get_dis(self, index: int):
            """
            返回出发顶点到index顶点的距离
            :param index:
            :return:
            """
            return self.dis[index]
    
        # 继续选择并返回新的访问顶点,比如这里的G完后,就是A点作为新的访问顶点(注意不是出发顶点)
        def update_arr(self):
            min_val = float('inf')
            index = 0
            for i in range(len(self.already_array)):
                if self.already_array[i] == 0 and self.dis[i] < min_val:
                    min_val = self.dis[i]
                    index = i
            # 更新 index 顶点被访问过
            self.already_array[index] = 1
            return index
    
        # 显示最后的结果,即将三个数组的情况输出
        def show_result(self):
            print('===================')
            # 输出already_array
            for item in self.already_array:
                print(item, end=' ')
            print()
            # 输出pre_visited
            for item in self.pre_visited:
                print(item, end=' ')
            print()
            # 输出dis
            for item in self.dis:
                print(item, end=' ')
            print()
            # 为了好看最后的最短距离,处理一下
            self.ver = Graph(vertex, matrix)
            count: int = 0
            for item in self.dis:
                if item != float('inf'):
                    print('{}到{}的最短距离为{}'.format(self.ver.vertex[self.index],self.ver.vertex[count],self.dis[count]))
                count += 1
            print()
    
    
    class Graph(object):
        def __init__(self, vertex: [], matrix: []):
            self.vertex = vertex  # 传入顶点数组
            self.matrix = matrix  # 传入邻接矩阵
            self.vv = None  # 已经访问顶点的集合
    
        def show_djs(self):
            self.vv.show_result()
    
        def show_graph(self):  # 显示图
            for col in self.matrix:
                print(col)
    
        # 迪杰斯特拉算法实现
        def djs(self, index: int):
            self.vv = VisitedVertex(len(self.vertex), index)
            self.update(index)  # 更新index下标顶点到周围顶点的距离和前驱结点
            for j in range(1, len(self.vertex)):
                index = self.vv.update_arr()  # 选择并返回新的访问顶点
                self.update(index)  # 更新index下标顶点到周围顶点的距离和前驱结点
    
        # 更新index下标顶点到周围顶点的距离和周围顶点的前驱顶点
        def update(self, index):
            length: int = 0
            # 根据遍历邻接矩阵的 matrix[index]
            for j in range(len(self.matrix[index])):
                # length 含义:出发顶点到index顶点的距离+从index顶点到j顶点的距离的和
                length = self.vv.get_dis(index) + self.matrix[index][j]
                # 如果j顶点没有被访问过,并且length小于出发顶点到j顶点的距离,就需要更新
                if not self.vv.is_visited(j) and length < self.vv.get_dis(j):
                    self.vv.update_pre(j, index)  # 更新j顶点的前驱为index顶点
                    self.vv.update_dis(j, length)  # 更新出发顶点到j顶点的距离
    
    
    if __name__ == '__main__':
        # 顶点
        vertex: [] = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
        # 邻接矩阵
        matrix: [] = [[0 for col in range(len(vertex))] for row in range(len(vertex))]
        # 用来表示一个极大的数
        F: float = float('inf')
        matrix[0] = [F, 5, 7, F, F, F, 2]
        matrix[1] = [5, F, F, 9, F, F, 3]
        matrix[2] = [7, F, F, F, 8, F, F]
        matrix[3] = [F, 9, F, F, F, 4, F]
        matrix[4] = [F, F, 8, F, F, 5, 4]
        matrix[5] = [F, F, F, 4, 5, F, 6]
        matrix[6] = [2, 3, F, F, 4, 6, F]
        # 创建Graph对象
        g = Graph(vertex, matrix)
        g.show_graph()
        # 测试迪杰斯特拉算法
        g.djs(6)
        g.show_djs()
    ''' 输出结果
    [inf, 5, 7, inf, inf, inf, 2]
    [5, inf, inf, 9, inf, inf, 3]
    [7, inf, inf, inf, 8, inf, inf]
    [inf, 9, inf, inf, inf, 4, inf]
    [inf, inf, 8, inf, inf, 5, 4]
    [inf, inf, inf, 4, 5, inf, 6]
    [2, 3, inf, inf, 4, 6, inf]
    ===================
    1 1 1 1 1 1 1 
    6 6 0 5 6 6 0 
    2 3 9 10 4 6 0 
    G到A的最短距离为2
    G到B的最短距离为3
    G到C的最短距离为9
    G到D的最短距离为10
    G到E的最短距离为4
    G到F的最短距离为6
    G到G的最短距离为0
    '''
    
    展开全文
  • 数据结构实验 迪杰斯特拉算法
  • 图的迪杰斯特拉算法,本人亲自将课本的代码打出来并进行了修改
  • 迪杰斯特拉算法实现;迪杰斯特拉--算法思想; 设给定源点为VsS为已求得最短路径的终点集开始时令S={Vs} 当求得第一条最短路径(Vs Vi)后S为{VsVi} 根据以下结论可求下一条最短路径 设下一条最短路径终点为Vj 则Vj只有 ...
  • 通过邻接矩阵的数据结构存储一副图结构。利用迪杰斯特拉算法(C++实现)求其最短路径。
  • 迪杰斯特拉算法(求最短路径)

    千次阅读 2022-01-21 15:07:50
    迪杰斯特拉算法(求最短路径) 迪杰斯特拉算法用于查找图中某个顶点到其它所有顶点的最短路径,该算法既适用于无向加权图,也适用于有向加权图。 注意,使用迪杰斯特拉算法查找最短路径时,必须保证图中所有边的权值...

    迪杰斯特拉算法(求最短路径)

    迪杰斯特拉算法用于查找图中某个顶点到其它所有顶点的最短路径,该算法既适用于无向加权图,也适用于有向加权图。

    注意,使用迪杰斯特拉算法查找最短路径时,必须保证图中所有边的权值为非负数,否则查找过程很容易出错。

    迪杰斯特拉算法的实现思路

    图 1 是一个无向加权图,我们就以此图为例,给大家讲解迪杰斯特拉算法的实现思路。

    在这里插入图片描述

    图 1 无向加权图

    假设用迪杰斯特拉算法查找从顶点 0 到其它顶点的最短路径,具体过程是:

    1. 统计从顶点 0 直达其它顶点的权值,如下表所示:

    表 1 顶点 0 直达其它顶点的权值

    123456
    总权值26
    路径0-10-20-30-40-50-6

    ∞ 表示两个顶点之间无法直达,对应的权值为无穷大。

    1. 表 1 中,权值最小的是 0-1 路径,它也是从顶点 0 到顶点 1 的最短路径(如图 2 所示)。原因很简单,从顶点 0 出发一共只有 0-1 和 0-2 两条路径,0-2 的权值本就比 0-1 大,所以从 0-2 出发不可能找得到比 0-1 权值更小的路径。

    在这里插入图片描述

    图 2 最短路径 0-1

    1. 找到最短路径 0-1 后,沿 0-1 路径方向查找更短的到达其它顶点的路径,并对表 1 进行更新。

    表 2 沿 0-1 最短路径更新表 1

    123456
    总权值262+5
    路径0-10-20-1-30-40-50-6

    绿色加粗的权值是已确认为最短路径的权值,后续选择总权值最小的路径时不再重复选择;红色加粗的权值为刚刚更新的权值。

    更新后的表格如表 2 所示,沿 0-1 路径可以到达顶点 3,且 0-1-3 的总权值比 0-3 更小。表 2 中,总权值最小的路径是 0-2,它也是从顶点 0 到顶点 2 的最短路径,如下图所示。

    在这里插入图片描述

    图 3 最短路径 0-2

    1. 重复之前的操作,沿 0-2 路径方向查找更短的到达其它顶点的路径。遗憾地是,从顶点 2 只能到达顶点 3,且 0-2-3 的总权值比表 2 中记录的 0-1-3 更大,因此表 2 中记录的数据维持不变。

    表 3 结合 0-2 最短路径更新表 2

    123456
    总权值267
    路径0-10-20-1-30-40-50-6
    1. 表 3 中,总权值最小的是 0-1-3,它也是顶点 0 到顶点 3 的最短路径。

    在这里插入图片描述

    图 4 最短路径 0-1-3

    沿 0-1-3 路径方向,查找到其它顶点更短的路径并更新表 3。更新后的表格为:

    表 4 结合 0-1-3 最短路径更新表 3

    123456
    总权值2677+107+15
    路径0-10-20-1-30-1-3-40-1-3-50-6
    1. 表 4 中,总权值最小的是 0-1-3-4,它是顶点 0 到顶点 4 的最短路径。

    在这里插入图片描述

    图 5 最短路径 0-1-3-4

    从顶点 4 出发,查找顶点 0 到其它顶点更短的路径并更新表 4。更新后的表格为:

    表 5 结合 0-1-3-4 最短路径更新表 4

    123456
    总权值267172217+2
    路径0-10-20-1-30-1-3-40-1-3-50-1-3-4-6
    1. 表 5 中,总权值最小的路径是 0-1-3-4-6,它是顶点 0 到顶点 6 的最短路径。

    在这里插入图片描述

    图 6 最短路径 0-1-3-4-6

    1. 从图 6 可以看到,只剩下顶点 0 到顶点 5 的最短路径尚未确定。从顶点 6 出发到达顶点 5 的路径是 0-1-3-4-6-5,对应的总权值为 25,大于表 5 中记录的 0-1-3-5 路径,因此 0-1-3-5 是顶点 0 到顶点 5 的最短路径。

    在这里插入图片描述

    图 7 最短路径 0-1-3-5

    由此借助迪杰斯特拉算法,我们找出了顶点 0 到其它所有顶点的最短路径,如下表所示:

    表 6 最短路径

    123456
    总权值267172219

    迪杰斯特拉算法的具体实现

    了解了迪杰斯特拉算法的实现过程之后,接下来分别编写 C、Java 和 Python 程序真正地实现迪杰斯特拉算法。

    仍以图 1 为例,迪杰斯特拉算法查找顶点 0 到其它顶点所有最短路径的 C 语言程序为:

    #include <stdio.h>
    #define V 20                   //顶点的最大个数
    #define INFINITY 65535
    typedef struct {
        int vexs[V];         //存储图中顶点数据
        int arcs[V][V];      //二维数组,记录顶点之间的关系
        int vexnum, arcnum;  //记录图的顶点数和弧(边)数
    }MGraph;
    //根据顶点本身数据,判断出顶点在二维数组中的位置
    int LocateVex(MGraph * G, int v) {
        int i = 0;
        //遍历一维数组,找到变量v
        for (; i < G->vexnum; i++) {
            if (G->vexs[i] == v) {
                break;
            }
        }
        //如果找不到,输出提示语句,返回-1
        if (i > G->vexnum) {
            printf("no such vertex.\n");
            return -1;
        }
        return i;
    }
    //构造无向有权图
    void CreateDG(MGraph *G) {
        printf("输入图的顶点数和边数:");
        scanf("%d %d", &(G->vexnum), &(G->arcnum));
        printf("输入各个顶点:");
        for (int i = 0; i < G->vexnum; i++) {
            scanf("%d", &(G->vexs[i]));
        }
        for (int i = 0; i < G->vexnum; i++) {
            for (int j = 0; j < G->vexnum; j++) {
                G->arcs[i][j] = INFINITY;
            }
        }
        printf("输入各个边的数据:\n");
        for (int i = 0; i < G->arcnum; i++) {
            int v1, v2, w;
            scanf("%d %d %d", &v1, &v2, &w);
            int n = LocateVex(G, v1);
            int m = LocateVex(G, v2);
            if (m == -1 || n == -1) {
                return;
            }
            G->arcs[n][m] = w;
            G->arcs[m][n] = w;
        }
    }
    //迪杰斯特拉算法,v0表示有向网中起始点所在数组中的下标
    void Dijkstra_minTree(MGraph G, int v0, int p[V], int D[V]) {
        int final[V];//为各个顶点配置一个标记值,用于确认该顶点是否已经找到最短路径
        //对各数组进行初始化
        for (int v = 0; v < G.vexnum; v++) {
            final[v] = 0;
            D[v] = G.arcs[v0][v];
            p[v] = 0;
        }
        //由于以v0位下标的顶点为起始点,所以不用再判断
        D[v0] = 0;
        final[v0] = 1;
        int k = 0;
        for (int i = 0; i < G.vexnum; i++) {
            int min = INFINITY;
            //选择到各顶点权值最小的顶点,即为本次能确定最短路径的顶点
            for (int w = 0; w < G.vexnum; w++) {
                if (!final[w]) {
                    if (D[w] < min) {
                        k = w;
                        min = D[w];
                    }
                }
            }
            //设置该顶点的标志位为1,避免下次重复判断
            final[k] = 1;
            //对v0到各顶点的权值进行更新
            for (int w = 0; w < G.vexnum; w++) {
                if (!final[w] && (min + G.arcs[k][w] < D[w])) {
                    D[w] = min + G.arcs[k][w];
                    p[w] = k;//记录各个最短路径上存在的顶点
                }
            }
        }
    }
    int main() {
        MGraph G;
        CreateDG(&G);
        int P[V] = { 0 };   // 记录顶点 0 到各个顶点的最短的路径
        int D[V] = { 0 };   // 记录顶点 0 到各个顶点的总权值
        Dijkstra_minTree(G, 0, P, D);
      
        printf("最短路径为:\n");
        for (int i = 1; i < G.vexnum; i++) {
            printf("%d - %d的最短路径中的顶点有:", i, 0);
            printf(" %d-", i);
            int j = i;
            //由于每一段最短路径上都记录着经过的顶点,所以采用嵌套的方式输出即可得到各个最短路径上的所有顶点
            while (P[j] != 0) {
                printf("%d-", P[j]);
                j = P[j];
            }
            printf("0\n");
        }
        printf("源点到各顶点的最短路径长度为:\n");
        for (int i = 1; i < G.vexnum; i++) {
            printf("%d - %d : %d \n", G.vexs[0], G.vexs[i], D[i]);
        }
        return 0;
    }
    

    迪杰斯特拉算法查找顶点 0 到其它顶点所有最短路径的 Java 程序为:

    import java.util.Scanner;
    public class Dijkstra {
        static int V = 9; // 图中边的数量
        public static class MGraph {
            int[] vexs = new int[V]; // 存储图中顶点数据
            int[][] arcs = new int[V][V]; // 二维数组,记录顶点之间的关系
            int vexnum, arcnum; // 记录图的顶点数和弧(边)数
        }
        public static int LocateVex(MGraph G, int V) {
            int i = 0;
            // 遍历一维数组,找到变量v
            for (; i < G.vexnum; i++) {
                if (G.vexs[i] == V) {
                    break;
                }
            }
            // 如果找不到,输出提示语句,返回-1
            if (i > G.vexnum) {
                System.out.println("顶点输入有误");
                return -1;
            }
            return i;
        }
        // 构造无向有权图
        public static void CreatDG(MGraph G) {
            Scanner scn = new Scanner(System.in);
            System.out.print("输入图的顶点数和边数:");
            G.vexnum = scn.nextInt();
            G.arcnum = scn.nextInt();
            System.out.print("输入各个顶点:");
            for (int i = 0; i < G.vexnum; i++) {
                G.vexs[i] = scn.nextInt();
            }
            for (int i = 0; i < G.vexnum; i++) {
                for (int j = 0; j < G.vexnum; j++) {
                    G.arcs[i][j] = 65535;
                }
            }
            System.out.println("输入各个边的数据:");
            for (int i = 0; i < G.arcnum; i++) {
                int v1 = scn.nextInt();
                int v2 = scn.nextInt();
                int w = scn.nextInt();
                int n = LocateVex(G, v1);
                int m = LocateVex(G, v2);
                if (m == -1 || n == -1) {
                    return;
                }
                G.arcs[n][m] = w;
                G.arcs[m][n] = w;
            }
        }
        // 迪杰斯特拉算法,v0表示有向网中起始点所在数组中的下标
        public static void Dijkstra_minTree(MGraph G, int v0, int[] p, int[] D) {
            int[] tab = new int[V]; // 为各个顶点配置一个标记值,用于确认该顶点是否已经找到最短路径
            // 对各数组进行初始化
            for (int v = 0; v < G.vexnum; v++) {
                tab[v] = 0;
                D[v] = G.arcs[v0][v];
                p[v] = 0;
            }
            // 由于以v0位下标的顶点为起始点,所以不用再判断
            D[v0] = 0;
            tab[v0] = 1;
            int k = 0;
            for (int i = 0; i < G.vexnum; i++) {
                int min = 65535;
                // 选择到各顶点权值最小的顶点,即为本次能确定最短路径的顶点
                for (int w = 0; w < G.vexnum; w++) {
                    if (tab[w] != 1) {
                        if (D[w] < min) {
                            k = w;
                            min = D[w];
                        }
                    }
                }
                // 设置该顶点的标志位为1,避免下次重复判断
                tab[k] = 1;
                // 对v0到各顶点的权值进行更新
                for (int w = 0; w < G.vexnum; w++) {
                    if (tab[w] != 1 && (min + G.arcs[k][w] < D[w])) {
                        D[w] = min + G.arcs[k][w];
                        p[w] = k;// 记录各个最短路径上存在的顶点
                    }
                }
            }
        }
        public static void main(String[] args) {
            MGraph G = new MGraph();
            CreatDG(G);
            int[] P = new int[V]; // 记录顶点 0 到各个顶点的最短的路径
            int[] D = new int[V]; // 记录顶点 0 到各个顶点的总权值
            Dijkstra_minTree(G, 0, P, D);
            System.out.println("最短路径为:");
            for (int i = 1; i < G.vexnum; i++) {
                System.out.print(i + " - " + 0 + " 的最短路径中的顶点有:");
                System.out.print(i + "-");
                int j = i;
                // 由于每一段最短路径上都记录着经过的顶点,所以采用嵌套的方式输出即可得到各个最短路径上的所有顶点
                while (P[j] != 0) {
                    System.out.print(P[j] + "-");
                    j = P[j];
                }
                System.out.println("0");
            }
            System.out.println("源点到各顶点的最短路径长度为:");
            for (int i = 1; i < G.vexnum; i++) {
                System.out.println(G.vexs[0] + " - " + G.vexs[i] + " : " + D[i]);
            }
        }
    }
    

    迪杰斯特拉算法查找顶点 0 到其它顶点所有最短路径的 Python 程序为:

    V = 20   #顶点的最大个数
    INFINITY = 65535    #设定一个最大值
    P = [0]*V  # 记录顶点 0 到各个顶点的最短的路径
    D = [0]*V  # 记录顶点 0 到各个顶点的总权值
    class MGraph:
        vexs = []*V   #存储图中顶点数据
        arcs = [[0]*V for i in range(V)]    #二维列表,记录顶点之间的关系
        vexnum = 0    #记录图的顶点数和弧(边)数
        arcnum = 0
    G = MGraph()
    #根据顶点本身数据,判断出顶点在二维数组中的位置
    def LocateVex(G,v):
        #遍历一维数组,找到变量v
        for i in range(G.vexnum):
            if G.vexs[i] == v:
                break
        #如果找不到,输出提示语句,返回-1
        if i>G.vexnum:
            print("顶点输入有误")
            return -1
        return i
    #构造无向有权图
    def CreateDG(G):
        print("输入图的顶点数和边数:",end='')
        li = input().split()
        G.vexnum = int(li[0])
        G.arcnum = int(li[1])
        print("输入各个顶点:",end='')
        G.vexs = [int(i) for i in input().split()]
        for i in range(G.vexnum):
            for j in range(G.vexnum):
                G.arcs[i][j] = INFINITY
        print("输入各个边的数据:")
        for i in range(G.arcnum):
            li = input().split()
            v1 = int(li[0])
            v2 = int(li[1])
            w = int(li[2])
            n = LocateVex(G,v1)
            m = LocateVex(G,v2)
            if m == -1 or n == -1:
                return
            G.arcs[n][m] = w
            G.arcs[m][n] = w
    CreateDG(G)
    #迪杰斯特拉算法,v0表示有向网中起始点所在数组中的下标
    def Dijkstra_minTree(G,v0,P,D):
        #为各个顶点配置一个标记值,用于确认该顶点是否已经找到最短路径
        final = [0]*V
        #对各数组进行初始化
        for i in range(G.vexnum):
            D[i] = G.arcs[v0][i]
        #由于以v0位下标的顶点为起始点,所以不用再判断
        D[v0] = 0
        final[v0] = 1
        k =0
        for i in range(G.vexnum):
            low = INFINITY
            #选择到各顶点权值最小的顶点,即为本次能确定最短路径的顶点
            for w in range(G.vexnum):
                if not final[w]:
                    if D[w] < low:
                        k = w
                        low = D[w]
            #设置该顶点的标志位为1,避免下次重复判断
            final[k] = 1
            #对v0到各顶点的权值进行更新
            for w in range(G.vexnum):
                if not final[w] and (low + G.arcs[k][w]<D[w]):
                    D[w] = low + G.arcs[k][w]
                    P[w] = k   #记录各个最短路径上存在的顶点
    Dijkstra_minTree(G,0,P,D)
    print("最短路径为:")
    for i in range(1,G.vexnum):
        print("%d - %d的最短路径中的顶点有:"%(i,0),end='')
        print("%d-"%(i),end='')
        j = i
        #由于每一段最短路径上都记录着经过的顶点,所以采用嵌套的方式输出即可得到各个最短路径上的所有顶点
        while P[j] != 0:
            print("%d-"%(P[j]),end='')
            j = P[j]
        print("0")
    print("源点到各顶点的最短路径长度为:")
    for i in range(1,G.vexnum):
        print("%d - %d : %d"%(G.vexs[0], G.vexs[i], D[i]))
    

    以上程序的执行过程为:

    输入图的顶点数和边数:7 9
    输入各个顶点:0 1 2 3 4 5 6

    输入各个边的数据:
    0 1 2
    0 2 6
    1 3 5
    2 3 8
    3 5 15
    3 4 10
    4 5 6
    4 6 2
    5 6 6
    最短路径为:
    1 - 0的最短路径中的顶点有: 1-0
    2 - 0的最短路径中的顶点有: 2-0
    3 - 0的最短路径中的顶点有: 3-1-0
    4 - 0的最短路径中的顶点有: 4-3-1-0
    5 - 0的最短路径中的顶点有: 5-3-1-0
    6 - 0的最短路径中的顶点有: 6-4-3-1-0
    源点到各顶点的最短路径长度为:
    0 - 1 : 2
    0 - 2 : 6
    0 - 3 : 7
    0 - 4 : 17
    0 - 5 : 22
    0 - 6 : 19

    展开全文
  • 主要介绍了js图数据结构处理 迪杰斯特拉算法代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 最短路径迪杰斯特拉

    2018-08-09 19:56:51
    最短路径问题是经典图论问题之一。从工程意义上讲,最短路径问题是对大量工程问题的直观抽象。 最典型的例子是在地图上寻找最短驾车路径。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,376
精华内容 6,150
关键字:

迪杰斯特拉

友情链接: mlclass-ex1.zip