数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

这篇具有很好参考价值的文章主要介绍了数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

问题分类 

无权图单源最短路径算法

思路

伪代码

时间复杂度

代码实现(C语言)

有权图单源最短路径算法

Dijkstra(迪杰斯特拉)算法

伪代码 

时间复杂度 

代码实现(C语言)

多源最短路径算法

两种方法

Floyd算法

代码实现(C语言)


问题分类 

最短路径问题的抽象

在网络中,求两个不同顶点之间的所有路径中,边的权值之和最小的那一条路径

  • 这条路径就是两点之间的最短路径(Shortest Path)
  • 第一个顶点为源点(Source)
  • 最后一个顶点为终点(Destination)

单源最短路径问题

从某固定源点出发,求其到所有其他顶点的最短路径。

  • (有向)无权图
  • (有向)有权图

多源最短路径问题

求任意两顶点间的最短路径

  

无权图单源最短路径算法

思路

按照递增的顺序找出源点到各个顶点的最短路

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

在这样的一个图中,先访问与源点距离为1的顶点:

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

 

接着去访问与源点距离为2的顶点:

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

 

最后访问与源点距离为3的顶点,就发现所有顶点都已经被访问过了:

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

 

这样的方式我们发现与BFS(广度优先搜索)类似,所以通过改动原本BFS的算法来实现。

伪代码

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

 与之前学习的BFS算法不一样的是,删去了visited数组,不再用这个来表示顶点是否被访问了;

而是添加了dist数组和path数组,

dist数组用于存储从起始顶点到每个顶点的最短路径长度。

在算法开始时,将所有顶点的初始距离设为-1(或者无穷大,一个足够大的值)来表示尚未计算出最短路径。

在算法执行过程中,每当找到一个更短的路径时,就会更新dist数组中对应顶点的值。

path数组用于存储从起始顶点到每个顶点的最短路径的前驱节点(即上一个节点)。

通过path数组,我们可以在搜索结束后从目标顶点回溯并恢复整个最短路径。(因为是反序所以可以利用堆栈来输出整个最短路径)

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

将顶点W的距离(即最短路径长度)更新为顶点V的距离加1。

这意味着通过顶点V可以到达顶点W,且路径长度比当前已知的最短路径长度更短。

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

更新顶点W的前驱节点为顶点V。这就帮助我们在找到最短路径后回溯并恢复整个路径。

时间复杂度

O(V + E)

其中 V 是顶点数,E 是边数。

  • 遍历每个顶点:O(V)
  • 对于每个顶点,访问其所有邻接顶点:O(E)

我们遍历了每个顶点一次,并且对于每个顶点,我们只访问了它的邻接顶点一次。

因此,该算法的时间复杂度为 O(V + E)。

注意:这个时间复杂度假设图的表示方式为邻接表,其中访问每个顶点的邻接顶点的时间复杂度为 O(1)。如果使用邻接矩阵表示图,那么访问每个顶点的邻接顶点的时间复杂度将变为 O(V),总的时间复杂度将变为 O(V^2)。

代码实现(C语言)

/* 
   邻接表存储 - 无权图的单源最短路算法
   输入:图Graph,距离数组dist[],路径数组path[],源点S
   输出:dist[]中记录了源点S到各顶点的最短距离,path[]中记录了最短路径的前驱顶点
   dist[]和path[]全部初始化为-1
*/

void Unweighted(LGraph Graph, int dist[], int path[], Vertex S)
{
    Queue Q;  // 定义队列Q,用于广度优先搜索
    Vertex V;  // 当前顶点V
    PtrToAdjVNode W;  // 指向当前顶点V的邻接点的指针W
    
    Q = CreateQueue(Graph->Nv);  // 创建空队列Q,最大容量为图的顶点数Nv
    dist[S] = 0;  // 初始化源点S的距离为0
    AddQ(Q, S);  // 将源点S入队

    while (!IsEmpty(Q))
    {
        V = DeleteQ(Q);  // 从队列Q中删除一个顶点V,作为当前顶点
        for (W = Graph->G[V].FirstEdge; W; W = W->Next)
        {
            /* 对V的每个邻接点W->AdjV */
            if (dist[W->AdjV] == -1)
            {
                /* 若W->AdjV未被访问过 */
                dist[W->AdjV] = dist[V] + 1;  // 更新W->AdjV到源点S的距离
                path[W->AdjV] = V;  // 将当前顶点V记录在S到W->AdjV的路径上
                AddQ(Q, W->AdjV);  // 将W->AdjV入队,继续广度优先搜索
            }
        }
    } /* while结束*/
}

有权图单源最短路径算法

Dijkstra(迪杰斯特拉)算法

  • 令S = {源点s + 已经确定了最短路径的顶点}
  • 对任一未收录的顶点v,定义dist[v]为s到v的最短路径长度,但该路径仅经过S中的顶点。即路径的最小长度
  • 该路径是按照递增的顺序生成的,则

1.真正的最短路必须只经过S中的顶点。

2.每次从未收录的顶点中选一个dist最小的收录(贪心算法)。

3.增加一个v进入S,可能影响另外一个w的dist值

对于第1点:

在算法的每一步,我们将一个顶点加入集合S,该顶点是在当前阶段中距离源点s的最短路径长度最小的顶点。由于我们每次只选择当前最短路径的顶点,所以可以确保这些顶点经过的路径是当前阶段中最短的路径。

对于第3点:

如果收录v使得s到w的路径变短,则s到w的路径一定经过v,并且v到w有一条边。

在每一步中,选择的顶点v是当前阶段中距离源点s最近的顶点,而且该距离是经过已确定最短路径顶点集合S的路径长度。

当将顶点v加入集合S后,我们更新其他顶点的dist值,以反映新的最短路径长度。如果从v到w之间不存在直接的边,那么根据Dijkstra算法的贪心策略,顶点w将不会被更新为新的最短路径。

所以是一定存在一条从v到顶点w的边,并且通过v的路径长度加上边的权重小于w当前的dist值,那么说明我们可以通过顶点v找到一条更短的路径来达到顶点w。因此,为了保证选择的是下一个最近的顶点,我们要先进行比较。即当前的dist值通过v的路径长度加上边的权重比较。

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

伪代码 

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

E<V,W>表示V到W的边上的权重。

时间复杂度 

邻接矩阵表示法

在使用邻接矩阵表示图的情况下,每次查找未收录顶点中dist最小者的时间复杂度为O(V),并且需要进行V次这样的查找。

在每次查找中,还需要遍历当前顶点的所有邻接顶点,即总共需要进行V次遍历。

因此,总的时间复杂度为O(V^2 + E)。

邻接表表示法

而在使用邻接表表示图的情况下,可以使用最小堆来查找未收录顶点中dist最小者,可以将时间复杂度降低到O(logV)。

在每次查找中,仅需遍历当前顶点的邻接表,即遍历的次数不会超过图中的边数E。因此,总的时间复杂度为O((V + E)logV)。

注意:在稀疏图(边的数量相对较少)的情况下,邻接表表示图的效率更高。而在稠密图(边的数量接近顶点数量的平方)的情况下,邻接矩阵表示图的效率更高。

代码实现(C语言)

/* 
   邻接矩阵存储 - 有权图的单源最短路算法
   输入:图Graph,距离数组dist[],路径数组path[],源点S
   输出:dist[]中记录了源点S到各顶点的最短距离,path[]中记录了最短路径的前驱顶点
   使用邻接矩阵表示图,INFINITY表示不存在的边
*/

Vertex FindMinDist(MGraph Graph, int dist[], int collected[])
{ 
    /* 返回未被收录顶点中dist最小者 */
    Vertex MinV, V;
    int MinDist = INFINITY;

    for (V = 0; V < Graph->Nv; V++)
    {
        if (collected[V] == false && dist[V] < MinDist)
        {
            /* 若V未被收录,且dist[V]更小 */
            MinDist = dist[V]; /* 更新最小距离 */
            MinV = V; /* 更新对应顶点 */
        }
    }
    if (MinDist < INFINITY) /* 若找到最小dist */
        return MinV; /* 返回对应的顶点下标 */
    else
        return ERROR;  /* 若这样的顶点不存在,返回错误标记 */
}

bool Dijkstra(MGraph Graph, int dist[], int path[], Vertex S)
{
    int collected[MaxVertexNum];
    Vertex V, W;

    /* 初始化:此处默认邻接矩阵中不存在的边用INFINITY表示 */
    for (V = 0; V < Graph->Nv; V++)
    {
        dist[V] = Graph->G[S][V];
        if (dist[V] < INFINITY)
            path[V] = S;
        else
            path[V] = -1;
        collected[V] = false;
    }
    /* 先将起点收入集合 */
    dist[S] = 0;
    collected[S] = true;

    while (1)
    {
        /* V = 未被收录顶点中dist最小者 */
        V = FindMinDist(Graph, dist, collected);
        if (V == ERROR) /* 若这样的V不存在 */
            break;      /* 算法结束 */
        collected[V] = true;  /* 收录V */
        for (W = 0; W < Graph->Nv; W++) /* 对图中的每个顶点W */
        {
            /* 若W是V的邻接点并且未被收录 */
            if (collected[W] == false && Graph->G[V][W] < INFINITY)
            {
                if (Graph->G[V][W] < 0) /* 若有负边 */
                    return false; /* 不能正确解决,返回错误标记 */
                /* 若收录V使得dist[W]变小 */
                if (dist[V] + Graph->G[V][W] < dist[W])
                {
                    dist[W] = dist[V] + Graph->G[V][W]; /* 更新dist[W] */
                    path[W] = V; /* 更新S到W的路径 */
                }
            }
        }
    } /* while结束*/
    return true; /* 算法执行完毕,返回正确标记 */
}

多源最短路径算法

两种方法

  • 方法1:直接将单元最短路算法调用V遍

在稀疏图的情况下,单源最短路径算法时间复杂度为O(V^2 + E);

现在是多源,要调用V遍,故而时间复杂度T为:O(V^3 + E*V)

  • 方法2:Floyd算法

这个算法用于稠密图,时间复杂度T直接就为:O(V^3)

在下面进行解释:

Floyd算法

对于稠密图的话,我们通常是可以使用邻接矩阵来表示图的,Floyd算法也是基于邻接矩阵的一个算法。

  •  = 路径的最小长度
  • ,即给出了i到j的真正最短距离
  • ,即初始的矩阵定义为:带权的邻接矩阵,对角元为0.表示结点到自身的距离为0
  • 当已经完成,递推到时:

最短路径时, = 。

最短路径时,该路径必定由两段最短路径组成数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

Floyd算法也是逐步地求出最短距离的,通过遍历所有可能的中间节点k,并不断尝试更新D[i][j]的值,Floyd算法逐步优化路径长度,最终找到图中所有节点对之间的最短路径。

假设我们有一个图,其中有节点i和节点j需要连接,并且我们已经知道了节点i到节点j的当前最短路径长度(存储在D[i][j]中)。

现在,我们引入一个中间节点k,想要通过节点k来尝试找到更短的路径,即尝试在节点i和节点j之间建立一条路径,其中包括节点k。

我们首先考虑从节点i到节点k的路径长度,这个距离我们可以在D数组中找到,即D[i][k]。接着,我们考虑从节点k到节点j的路径长度,同样可以在D数组中找到,即D[k][j]。

现在,我们将这两段路径长度加在一起,得到D[i][k] + D[k][j]。这个值表示通过节点k连接的从节点i到节点j的路径长度。

接下来,我们将这个通过节点k的路径长度与当前已知的最短路径长度(即D[i][j])进行比较。

  • 如果通过节点k的路径长度更短,那么我们更新D[i][j]的值为D[i][k] + D[k][j],表示我们找到了一条经过节点k的更短路径。
  • 如果通过节点k的路径长度并不比当前已知的最短路径长度更短,那么我们不做任何更改,保持D[i][j]不变。

代码实现(C语言)

/* 邻接矩阵存储 - 多源最短路算法 */

bool Floyd(MGraph Graph, WeightType D[][MaxVertexNum], Vertex path[][MaxVertexNum]) 
{
    Vertex i, j, k;

    /* 初始化 */
    for (i = 0; i < Graph->Nv; i++)
    {
        for (j = 0; j < Graph->Nv; j++) 
        {
            D[i][j] = Graph->G[i][j];  // 初始化最短路径数组D为图的邻接矩阵
            path[i][j] = -1;           // 初始化路径数组path为-1,表示当前节点间没有中间节点
        }
    }

    for (k = 0; k < Graph->Nv; k++) 
    {
        for (i = 0; i < Graph->Nv; i++) 
        {
            for (j = 0; j < Graph->Nv; j++) 
            {
                if (D[i][k] + D[k][j] < D[i][j]) 
                {  // 如果通过中间节点k可以获得更短的路径
                    D[i][j] = D[i][k] + D[k][j];    // 更新节点i到节点j的最短路径长度
                    if (i == j && D[i][j] < 0) 
                    {    // 若发现负值圈,即存在权重之和为负的回路
                        return false;               // 不能正确解决,返回错误标记
                    }
                    path[i][j] = k;                  // 更新节点i到节点j的路径经过的中间节点为k
                }
            }
        }
    }
    return true;  // 算法执行完毕,返回正确标记
}

 


end


学习自:MOOC数据结构——陈越、何钦铭文章来源地址https://www.toymoban.com/news/detail-480410.html

到了这里,关于数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构学习记录——图应用实例-拯救007(问题描述、解题思路、伪代码解读、C语言算法实现)

    目录 问题描述  解题思路 伪代码  总体算法 DFS算法 伪代码解读 总体算法 DFS算法 具体实现(C语言) 在老电影“007之生死关头”(Live and Let Die)中有一个情节,007被毒贩抓到一个鳄鱼池中心的小岛上,他用了一种极为大胆的方法逃脱 —— 直接踩着池子里一系列鳄鱼的大脑

    2024年02月05日
    浏览(78)
  • 数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。

    最短路径的算法有两个, Dijkstra算法 和 Floyd算法 。 Dijkstra算法 解决的是 单源 最短路径问题 。 Floyd算法解决的是 多源 最短路径问题,并且可以处理负权图 。 今天要讲的就是Dijkstra算法。 加: feng--Insist (大写的i),进java交流群讨论互联网+技术。可索要PPT等资料。 其他资料

    2024年02月11日
    浏览(58)
  • 数据结构线性结构(二)6迷宫最短路径

       

    2024年02月08日
    浏览(33)
  • 数据结构——图的最短路径

    在图中,求两个不同顶点间的不同路径中,边的权值和最小的那条路径。这条路径就叫做 最短路径(Shortest Path) ,第一个顶点叫做 源点(Source) ,最后一个顶点叫做 终点(Destination) 。 单源最短路径问题: 从某固定源点出发,求其到所有其他顶点的最短路径。         包

    2024年02月03日
    浏览(51)
  • 数据结构--6.0最短路径

    目录 一、迪杰斯特拉算法(Dijkstra) 二、弗洛伊德算法(Floyd)   在网图和非网图中,最短路径的含义是不同的。 ——网图是两顶点经过的边上的权值之和最少的路径。                                                                     ——非网图是两顶点之间经

    2024年02月10日
    浏览(30)
  • 数据结构--最短路径 Floyd算法

    F l o y d 算法:求出每⼀对顶点之间的最短路径 color{red}Floyd算法:求出每⼀对顶点之间的最短路径 Fl oy d 算法:求出每 ⼀ 对顶点之间的最短路径 使⽤动态规划思想,将问题的求解分为多个阶段 对于n个顶点的图G,求任意⼀对顶点 V i → V j V_i to V_j V i ​ → V j ​ 之间的最短

    2024年02月12日
    浏览(38)
  • 数据结构--最短路径 Dijkstra算法

    计算  b e g i n  点到各个点的最短路 color{red}计算 begin 点到各个点的最短路 计算   b e g in   点到各个点的最短路 如果是无向图,可以先把无向图转化成有向图 我们需要2个数组 final[] (标记各顶点是否已找到最短路径)与 dis[] (最短路径⻓度)数组 Dijkstra算法是一种用于

    2024年02月12日
    浏览(37)
  • 图的最短路径 (数据结构实验报告)

    一、实验目的 讲清楚进行本实验后要学到的知识、掌握的数据结构及其定义和表示方法,讲清楚所采用的算法。 掌握图结构的(邻接矩阵)输入方法 掌握图结构的说明、创建以及图的存储表示(邻接矩阵) 掌握最短路径算法原理 掌握最短路径算法的编程实现方法 二、实验

    2024年02月06日
    浏览(50)
  • 大二数据结构实验(迪杰斯特拉最短路径)

    大二数据结构实验,有详细批注,代码可以直接运行,希望可以给大家提供到帮助。 实验目的 掌握图的邻接矩阵的存储定义。 掌握图的最短路径(Dijsktra)算法的实现。 实验内容 设计校园平面图,所含景点不少于8个。以图中顶点表示学校内各景点,存放景点的名称、景点

    2024年02月12日
    浏览(42)
  • 【数据结构】图解:迪杰斯特拉算法(Dijkstra)最短路径

    目录 一、方法描述 二、例题一  ​编辑 三、例题二  有图如上,用迪杰斯特拉算法求顶点A到其余各顶点的最短路径,请问1.第一步求出的最短路径是A到C的最短路径2.第二步求出的是顶点A到顶点B/F的最短路径3.顶点A到D的最短路径长度是__25___ (填数字)4.顶点A到顶点F的最短路

    2024年02月12日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包