Dijkstra算法&&邻接表数组

后文:Dijkstra算法堆/优先队列优化

前言

  1. 本文将直接使用邻接表的数组形式进行图的存储,邻接矩阵的存储方式在此算法的实现上较为简单,邻接表的链式存储较为麻烦,且申请释放内存会消耗大量时间,在此不再赘述。
  2. 本文使用的邻接表数组存储来源于《啊哈!算法》,由于我水平有限,只能暂时先使用这种包含5个数组的邻接表。
  3. 本文中的算法不记录路径只记录距离。
  4. 本文中所有数组的第一个存储单元即a[0],都没有被使用。
  5. 此算法不能解决带有负权边的图,因此我们规定本文中的图里面不存在负权边。
  6. 代码采用C++实现,不过只要有C语言的基础就可以看懂,没有用到很多C++的东西。
  7. 若对本文存在疑问、意见或建议,欢迎评论及与我本人联系。
  8. 算法的优化详见后文。

术语简介

  1. 权值:表示两点之间的距离、耗费等具有某种意义的数值
  2. 弧:有向的边,在图上用箭头表示,<x,y>表示从点x到点y有一条弧(请注意<y,x>与其是不同的两条弧)
  3. 弧尾:弧的起点,x
  4. 弧头:弧的终点,y
  5. 路径:由连续的弧构成的顶点序列,在图中,存在路径的两点之间不一定存在直达的弧
  6. 入边:以某点为弧头的边
  7. 出边:以某点为弧尾的边

Dijkstra入门

最短路径问题

在图论中,最短路径是一类十分常见的问题,常见的有SSSP(Single-source Shortest Paths,单源最短路径)和APSP(All Pairs Shortest Paths,多源最短路径。而今天讲到的Dijkstra算法,主要用来解决SSSP问题。它指的是以某个点为起点,从该点到其余各个顶点的最短路程/最小代价。此算法也可以解决APSP问题,只是它较为复杂,不推荐使用。请注意此类问题与最小生成树问题的区别与联系:最小生成树问题结果会涉及到图中的所有顶点,而最短路径问题的结果可能只涉及到图中的一部分顶点。

算法思想介绍

在这里插入图片描述
以此有向图为例,为了求解从顶点1开始到各顶点的最短路径,Dijkstra算法首先确定了两个集合A、B,其中A集合中包含已经确定最短路径的顶点,B集合包含未确定最短路径的点。其次我们需要一个数组dis来记录从起点到各个顶点的最短距离,一个数组book来记录顶点是否在A集合中。
接下来我们要对上述两个数组进行初始化,这里我们以1号顶点作为起点。先将book数组全部置为false,表示所有点都未确定最短距离。同时对dis数组进行初始化,访问邻接表,若起点与点i之间存在弧,则将dis[i]置为弧的权值,否则置为inf(无穷)。全部初始化完成后,将起点——1号顶点加入集合A中,即book[1]置为true,众所周知自己到自己的最短路径是0,因此将dis[1]置为0。至此准备工作完成。
此时数组情况如下:

编号 book dis
1 true 0
2 false 1
3 false 12
4 false inf
5 false inf
6 false inf

下面正式开始算法!!!(敲黑板.jpg)

  1. 从除1号顶点之外的其他所有顶点中(即集合B中的顶点)找到离1号顶点最近的顶点,即从以1号顶点为弧尾/起点的弧中找到权值最小的那条弧(这里就是顶点2啦),并将其加入集合A中(即book[2]=true)
  2. 接下来对其余顶点进行处理。以在集合B中的顶点j为弧头/终点,访问以2号顶点为弧尾/起点的弧,观察以2号点为中转点,从1号到j号顶点的路径长度是否缩短,即dis[j]是否大于dis[2]+弧<2,j>权值 ,若大于,则进行松弛。此时我们首先发现,dis[3]>dis[2]+9,因此将dis[3]更新为10。此时数组情况如下:
编号 book dis
1 true 0
2 true 1
3 false 10
4 false inf
5 false inf
6 false inf

紧接着我们又发现,dis[4]>dis[2]+3,因此将dis[4]更新为4。此时数组情况如下

编号 book dis
1 true 0
2 true 1
3 false 10
4 false 4
5 false inf
6 false inf
  1. 重复上述过程,直到所有的顶点都进入集合A中,算法结束。
    接下来发现集合B中离1号顶点最近的顶点是4号,进行处理后数组如下:
编号 book dis
1 true 0
2 true 1
3 false 8
4 true 4
5 false 17
6 false 19

继续寻找,这次选择3号顶点,进行处理后数组如下

编号 book dis
1 true 0
2 true 1
3 true 8
4 true 4
5 false 13
6 false 19

继续寻找,这次选择5号顶点,进行处理后数组如下:

编号 book dis
1 true 0
2 true 1
3 true 8
4 true 4
5 true 13
6 false 17

继续寻找,这次选择6号顶点,将其加入集合A后,由于它没有出边,且此时所有顶点都已在集合A中,因此无需进行处理。

算法实现

构造出的输入数据如下:

6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4

六个顶点九条边

代码如下:

#include<iostream>//Dijkstra迪杰斯克拉算法模板
#define inf 999999999//定义inf
using namespace std;

int cur=1;//记录当前边的编号
int dis[10];//记录源点到各顶点的最短路径
bool book[10];//记录已经找到最短路径的点
int from[10],to[10],value[10];//分别表示起点,终点,权值
int start[10],nt[10];//分别表示起点和"链域"
<
  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值