数据结构(22)图的最短路径

前言

本篇是数据结构系列的最后一篇了,当然,涉及到数据结构还有一些排序算法、搜索算法没有写出来,以后会慢慢补上。

我们说的最短路径,指的是从有向图中,某一顶点A到另一顶点B的最短路径。

这就有两种情况:第一种是不考虑边的权值,而考虑中转次数,求的是A到B最少需要经过几条边。第二种则是考虑边的权值,求从A到B路径上权值之和最短的一条。

如图所示,从A到E的路径有:A-E(100),A-D-C-E(60),A-D-E(90),A-B-C-E(70)等等。假如是第一种情况,需要找到的是A-E边,而第二种情况,需要找到的是A-D-C-E边。

img_1

这里我们说的最短路径是第二种情况,所实现的算法为迪杰斯特拉算法。

迪杰斯特拉算法

迪杰斯特拉算法的思路是:

  1. 从要寻找的起点A开始,维护一个记录到达其他顶点X最短距离的数组dist,若不可达,则存为MAX_VALUE。

  2. 数组中拥有最短距离的顶点B纳入A顶点集合,然后去统计 从B到其余顶点X的距离,加上A到B的距离,是否小于之前要到达X的最短距离,若小于,则更新最短距离数组。

    注:最短距离数组中存放的可能是A直达X的距离,也可能是A到C,C再到X的距离。总之存储的是当前情况下A到X的最短距离。

  3. 重复第二步,直到找完最后一个顶点为止。

很显然,当一个顶点被纳入A顶点集合之后,是不会再重复纳入的。这就要求我们再维护一个visited数组,记录当前顶点是否已经被纳入集合。同时,还需要一个path数组记录到达每一个顶点的路径。

直接看例子:

img_2

  1. 求从A出发到达各个顶点的最短路径,此时初始化数组,dist数组中记录的是A到其余顶点边的权值,若无边,则为最大值(表示不可达)。path数组记录了A到达各个顶点的路径,A无法到达自己,记录为-1,C不可达,记录为最大值。而visited数组记录了已经纳入A集合的顶点,此时只有A。

  2. 从dist数组中找到最短距离的顶点,此时为B,将B纳入A顶点集合(visited[1] = 1)。统计从B到其余顶点的距离,加上A-B的距离10,是否小于dist数组中存储的距离。可以发现,A-B-C为60,小于原来的A-C的最大值,更新dist数组。并且将到达C的路径改为B的下标(path[2] = 1)。

    注:path记录了A到其余顶点的路径。path[2] 值为 1,意味着要到达C,首先要到达B(path[1]),而要到达C,首先要到达path[0],path[0] 值为 -1,说明就是从path[0]出发的,这样就可以找到A-B-C的路径。

  3. 从dist数组中找到最短距离的顶点,此时为D,将D纳入A顶点集合(visited[3] = 1)。统计从D到其余顶点的距离,加上A-D的距离30,是否小于dist数组中存储的距离。可以发现,A-D-E为90,小于原来A-E的最大值;A-D-C为50,也小于原来的A-B-C最大值,更新dist数组。并且修改到达E、C的路径为D的下标。

img_3

  1. 从dist数组中找到最短距离的顶点,此时为C,将C纳入A顶点集合(visited[2] = 1)。统计从C到其余顶点的距离,加上A-C的距离50,是否小于dist数组中存储的距离。可以发现,A-D-C-E为60,小于原来A-D-E的最大值,更新dist数组。并且修改到达E的路径为C的下标。

  2. 从dist数组中找到最短距离的顶点,此时为E,将E纳入A顶点集合(visited[4] = 1)。统计从E到其余顶点的距离,加上A-E的距离60,是否小于dist数组中存储的距离。此时无可更新的数据。

当整个迪杰斯特拉算法运行结束后,我们就可以得到A到达每一个顶点的最短距离dist[],和路径path[]。

全部代码

Main.c
#include "GraphMtx.h"

int main(int argc, const char * argv[]) {
   
    GraphMtx gm;
    InitGraph(&gm);
    InsertVertex(&gm,'A');
    InsertVertex(&gm,'B');
    InsertVertex(&gm,'C');
    InsertVertex(&gm,'D');
    InsertVertex(&gm,'E');
 
    InsertEdge(&gm,'A','B',10);
    InsertEdge(&gm,'A','D',30);
    InsertEdge(&gm,'A','E',100);
    InsertEdge(&gm,'B','C',50);
    InsertEdge(&gm,'C','E',10);
    InsertEdge(&gm,'D','C',20);
    InsertEdge(&gm,'D','E',60);
    ShowGraph(&gm);
    
    
    int n = gm.NumVertices;
    int *dist = (int *)malloc(sizeof(int) * n);
    int *path = (int *)malloc(sizeof(int) * n);
    assert
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值