【图】最短路径--迪杰斯特拉(Dijkdtra)算法

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。

它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。

算法思想
每次找到离源点最近的一个顶点,然后以该顶点为中心,然后得到源点到其他顶点的最短路径。贪心算法。

举例分析

以邻接矩阵为存储图

这里写图片描述

注:上图中,邻接矩阵的对称线也是无穷大,在初始时默认为无穷大。可以看上篇博客,图的存储。

(1) 用dis数组来存储源点1到其他顶点的初始路径,标记1号顶点,
这里写图片描述

此时dis数组中的值称为最短路径的估计值。

(2) 从dis数组中找出离源起点最近的点2号,以2号顶点为源点进行找最近的顶点。把2号顶点标记,表示已经有最小值。

以2号顶点为源点,看2号顶点有哪些出边,看能不能优化,再短一些
2->3:9,2->4:3
而dis中最短路径的估计值,1->2:1, 1->3:12
那么结合一下 1->2->3:1+9=10,比1->3:12 小,
1->2:1 和 2->4:3,那么1->2->4:4
所以要更新 dis中的最短路径估计值,

这里写图片描述

(3) 此时1号和2号顶点已经标记,表示已经最小值,现在在3号和4号找,4号顶点距离源点最近,所以以4号顶点进行找,标记4号顶点

4号的出边:
4->3:4,4->5:13,4->6:15。
用刚才的方法进行更新估计值。
1->3:10 比 1->4->3:4+4=8,大,所以更新
1->4:4,4->5:13+4=17,更新。
1->4:4,4->6:15+4 = 19。更新
这里写图片描述

(4)从3号,5号,6号,找最短路径8,标记3号顶点。
以相同的方法进行更新。

这里写图片描述

(5)从5号和6号顶点查找,标记5号。
以相同的方法进行更新。

这里写图片描述

(6)此时剩余6号顶点,6号的出边没有,
此时所有的顶点都以遍历完,dis中的值就是最终的结果。

这里写图片描述

步骤:
(1)将所有的顶点分为两个部分,已知最短路径的顶点集合P和未知的顶点集合Q,初始时,P中只有一个源顶点1号。这里用book数组来标记顶点是否在P中,1表示在P中,0表示在Q中。

dis数组来记录最短路径,数组下标来表示顶点的下标。

设置源点1到到其他顶点的路径值,放置到dis中。

(2)在dis中找到源点s到其他顶点的最短路径u顶点,将其加入P集合,并考察以x顶点为起点的出边,然后对dis 进行更新。即:如果存在一条从u到v的边,那么可以拓展一条从s到u再到v的边,路径长度为dis[u]+edge[u] [v] ,如果这个值比目前的值dis[v]小,那么就进行更新。

(3)重复第2步,直到Q为空,即book都被标记,此时dis数组中就是源点到各个顶点的最短路径。

代码实现

    //最短路径,Dijkdtra算法
    vector<int> Dijkdtra(const V& start)
    {
        //保存结果值,下标为顶点元素的下标,
        vector<int> dis(_ver.size());
        //记录已确定的最小的值的顶点
        vector<int> book(_ver.size(), 0);

        //获取起始位置的下标,
        int index = GetIndexOfVertex(start);
        book[index] = 1;

        //初始化dis
        for (size_t idx = 0; idx < _edge[0].size(); ++idx)
            dis[idx] = _edge[index][idx];       


        while (true)
        {
            int u = -1;//新的源点下标
            int min = INT_MAX;
            //寻找未被处理过,且距离最小的点
            for (size_t i = 0; i < dis.size(); ++i)
            {
                if (book[i] == 0 && dis[i] < min)
                {
                    min = dis[i];
                    u = i;//记录最近的顶点下标               
                }

            }
            //都处理过,退出
            if (u == -1)
                break;
            book[u] = 1;
            //步骤2
            for (size_t v = 0; v < _edge[0].size(); ++v)
            {
                if (_edge[u][v] < INT_MAX)
                {
                    if (dis[v] > _edge[u][v] + dis[u])
                        dis[v] = _edge[u][v] + dis[u];
                }
            }
        }
        return dis;
    }
  • 35
    点赞
  • 130
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值