单源最短路径算法——Dijkstra算法(迪杰斯特拉算法)
一 综述
Dijkstra算法(迪杰斯特拉算法)主要是用于求解有向图中单源最短路径问题。其本质是基于贪心策略的(具体见下文)。其基本原理如下:
(1)初始化:集合vertex_set初始为{source_vertex},dist数组初始值为$dist[i] = G.arc[source\_vertex][i],i=0,1,\ldots,n-1$
(2)从顶点集合V-vertex_set中选出$v_j$,满足$dist[j] = Min\left\{dist[i] | v_i∈V-vertex\_set\right\}$,那么$v_j$就是当前求得的一条从source_vertex出发的最短路径的终点,并令$vertex\_set = vertex\_set ∪ j$。
(3)修改从source_vertex出发到集合V-vertex_set上任一顶点$v_k$可达的最短路径长度:如果$dist[j] + arc[j][k] < dist[k]$,则令$dist[k] = dist[j] + G.arc[j][k]$。
(4)重复(2)~(3)操作共n-1次,直到所有的顶点都包含在vertex_set中。
具体代码如下:
#include<iostream>
#include<unordered_map>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<sstream>
#include<set>
#include<map>
using namespace std;
#define MAX_NUM 100
#define INF 0x7fffffff
/*
dijkstra算法的实现
参数说明:
1.source_vertex:表示源点
2.G:表示图(此处以邻接矩阵为例)
3.dist数组:表示源点到其他所有顶点的最短路径的长度。例如dist[j]表示源点到顶点Vj的最短路径长度
4.vertex_set数组:表示已找到最短路径的顶点的集合,其中vertex_set[i] = true表示顶点dist[i]已经最终确定
5.pre数组:用以表示顶点的最短路径的前驱顶点。例如,pre[i] = k表示顶点vi的最短路径上的前驱顶点为vk。
*/
class Graph
{
public:
int vertexNum;//顶点个数
int arcNum;//弧的个数
int vertex[MAX_NUM];//顶点表
int arc[MAX_NUM][MAX_NUM] = {{0,INF,10,INF,30,100},
{INF,0,5,INF,INF,INF},
{INF,INF,0,50,INF,INF},
{INF,INF,INF,0,INF,10},
{INF,INF,INF,20,0,60},
{INF,INF,INF,INF,INF,0}};//弧信息表
};
void Dijkstra(Graph &G,int source_vertex,int dist[],bool vertex_set[],int pre[])
{
int _min;
int k;
int vertex_num = G.vertexNum;//顶点个数
//初始化
for(int i = 0 ; i < vertex_num; i++)
{
dist[i] = G.arc[source_vertex][i];//初始化dist数组
if(i == source_vertex)
vertex_set[i] = true;//将顶点source_vertex加入vertex_set数组
else
vertex_set[i] = false;
pre[i] = 0;//前驱顶点为v0,后面会更新
}
//遍历n-1次,每次找到一个顶点的最短路径
for(int i = 1; i < vertex_num; i++)
{
_min = INF;//初始化辅助变量
//在未获取最短路径的顶点中,找到离source_vertex最近的顶点vk。
for(int j = 0; j < vertex_num; j++)
{
if(vertex_set[j] == false && dist[j] < _min)
{
_min = dist[j];
k = j;
} }
//此时源点到顶点vk的最短距离已经找到,即dist[k]已经确定,将k加入到vertes_set中
vertex_set[k] = true;
//对dist[j]进行检验更新
for(int j = 0; j < vertex_num; j++)
{
int tmp = (G.arc[k][j]== INF ? INF : _min + G.arc[k][j]);//防止溢出
if(vertex_set[j] == false && tmp < dist[j])
{
dist[j] = _min + G.arc[k][j];//更新满足条件的顶点的dist数组值
pre[j] = k;//更新前驱顶点
}
}
} } int main()
{
Graph G;
G.vertexNum = 6;
int source_vertex = 0;
int dist[6] = {0};
bool vertex_set[6];
int pre[100] = {0};
Dijkstra(G,source_vertex,dist,vertex_set,pre);
cout<<dist[0]<<endl; }
该算法的时间的时间复杂度为O(n^3),n为图中顶点的个数。其中比较核心的部分是最里面的两个for循环,第一个for循环对应的是第二步;而第二个for循环对应的是第三步;最外层的for循环对应的是第四步。
此外,(1)由于INF表示的int能表示的最大值,它加上一个正值必然会溢出,所以应该考虑溢出的问题。(或者别把INF设成这么大,设小些)
(2)我们默认带权有向图在表示时,若果i == j,则w(i,j)=0而不是w(i,j)=∞。
二 相关理论和注意事项
1.Dijkstra算法的核心之处在于:从源点$v_0$到目标顶点$v_j$的最短路径,要么是弧$(v_0,v_j)$;要么是中间只经过vertex_set中的顶点而最后达到顶点$v_j$的路径。
证明如下:假设符合上述结论的最短路径为L1,假设从$v_0$到顶点$v_j$的最短路径上有一个顶点不在vertex_set中,则说明存在一条终点不在vertex_set中而长度比此路径更短的路径,设该路径为L2。但是,这是与事实相矛盾的。因为我们是按路径长度递增的次序来产生个最短路径的,故长度比此路径短的所有路径都已经产生,它们的终点必然在vertex_set中;即若L2 < L1,L2中的终点必然在集合vertex_set中。
2.更新集合vertex_set只在第二步,相当于每次选出最小的dist[j],实质就是一个贪心的过程;而第三部相当于更新每个满足条件的dist[j]。第二步和第三步就体现了理论中的两种情况。
3.可以根据pre数组追溯到源点到目标顶点的最短路径序列。
4.Dijkstra算法不适用于边上带有负权重的有向图,如果边上有负值的话,有可能出现当与vertex_set内某点(记为A)以负边相连的点(记为B)确定最短路径时,它的最短路径加上负边的权值结果小于A原先确定的最短路径的长度,而此时的A在dijkstra算法下是无法更新的。例如:
根据Dijkstra算法而言,如果求$v_0$到其他顶点的最短路径的话,首先一开始确定的是$dist[0] = 0$且$vertex\_set[0] = true$,然后由于$dist[2]$是最小的,所以$vertex\_se[2] = true$即$v_0$到$v_2$的最短路径长度为5,然而实际上$v_0$到$v_1$再到$v_2$的距离明显更小,所以实际上$v_0$到$v_2$的最短路径长度为应为7 - 5 = 2;但是$dist[2]$无法再更新了,所以此时利用Dijkstra算法求得的最短路径是错误的。
单源最短路径算法——Dijkstra算法(迪杰斯特拉算法)的更多相关文章
- 全局路径规划算法Dijkstra(迪杰斯特拉算法)- matlab
参考博客链接:https://www.cnblogs.com/kex1n/p/4178782.html Dijkstra是常用的全局路径规划算法,其本质上是一个最短路径寻优算法.算法的详细介绍参考上述 ...
- 数据结构之---C语言实现最短路径之Dijkstra(迪杰斯特拉)算法
此处共同拥有两段代码: 一. 这段代码比較全面,当中參考了github上的相关源代码. 能够说功能强大. //Dijkstra(迪杰斯特拉算法) #include <stdio.h> #i ...
- 【最短路径之dijkstra(迪杰斯特拉)算法】
这一章主要介绍最短路径的算法之一,dijkstra算法. 概念 :迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点 ...
- Dijkstra【迪杰斯特拉算法】
有关最短路径的最后一个算法——Dijkstra 迪杰斯特拉算法是由荷兰计算机科学家迪杰斯特拉于1959 年提出的,因此又叫迪杰斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路 ...
- dijkstra算法(迪杰斯特拉算法)
dijkstra算法(迪杰斯特拉算法) 用途:有向图最短路径问题 定义:迪杰斯特拉算法是典型的算法,一般的表述通常有两种方式,这里均采用永久和临时标号的方式,该算法要求图中不存在负权边 用永久和临时标 ...
- Java 迪杰斯特拉算法实现查找最短距离
迪杰斯特拉算法 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是 ...
- 图->最短路径->单源最短路径(迪杰斯特拉算法Dijkstra)
文字描述 引言:如下图一个交通系统,从A城到B城,有些旅客可能关心途中中转次数最少的路线,有些旅客更关心的是节省交通费用,而对于司机,里程和速度则是更感兴趣的信息.上面这些问题,都可以转化为求图中,两 ...
- 单源最短路径-迪杰斯特拉算法(Dijkstra's algorithm)
Dijkstra's algorithm 迪杰斯特拉算法是目前已知的解决单源最短路径问题的最快算法. 单源(single source)最短路径,就是从一个源点出发,考察它到任意顶点所经过的边的权重之 ...
- 【算法导论】单源最短路径之Dijkstra算法
Dijkstra算法解决了有向图上带正权值的单源最短路径问题,其运行时间要比Bellman-Ford算法低,但适用范围比Bellman-Ford算法窄. 迪杰斯特拉提出的按路径长度递增次序来产生源点到 ...
随机推荐
- [spring源码] 小白级别的源码解析ioc(二)
之前一篇,整体描述了一下 Spring的整体概况和 jar包的介绍. 现在开始进入具体的源码解析,从本篇开始,先介绍spring的ioc容器.之前也看过一些介绍spring源码的, 有的是只讲整体的接 ...
- CSS font-family字体大合集
在写文字内容占大篇幅的页面是,总是会面临着改变字体的需求,以下为font-family常用合集以及一部分文字效果: windows常见内置中文字体 字体中文名 字体英文名 ...
- 依赖注入原理---IoC框架
先来讲一讲,一个简单的依赖注入例子. 1. 依赖 如果在 Class A 中,有 Class B 的实例,则称 Class A 对 Class B 有一个依赖.例如下面类 Human 中用到一个 Fa ...
- QComboBox样式
https://blog.csdn.net/lys211/article/details/43956979https://blog.csdn.net/x_nazgul/article/details/ ...
- vue中父组件给子组件传值,子组件给父组件传值
1.父组件传给子组件 父元素中 子元素中(通过props传值) 2.子组件传给父组件 子元素中(this.$emit(传过去的名字,传的参数)) 父元素中 通过changeShow的参数data 把修 ...
- zabbix3.4.7页面中文乱码
无须重启任何服务,刷新页面即可.
- 线程基础:多任务处理——MESI协议以及带来的问题:伪共享
1.概述 本文和后续文章将着眼CPU的工作原理阐述伪共享的解决方法和volatile关键字的应用. 2.复习CPU工作原理2.1.CPU工作原理要清楚理解本文后续内容,就需要首先重新概述一下JVM的内 ...
- Java集合类框架的最佳实践有哪些?
1.根据应用需要正确选择要使用的集合类型对性能非常重要,比如:假如知道元素的大小是固定的,那么选用Array类型而不是ArrayList类型更为合适. 2.有些集合类型允许指定初始容量.因此,如果我们 ...
- js获取table中的列的数字的和
function getTdValue(a) { var tableId = document.getElementById("tab"); var num; for(var i= ...
- jQuery-2.DOM---节点的复制与替换
DOM拷贝clone() 克隆节点是DOM的常见操作,jQuery提供一个clone方法,专门用于处理dom的克隆 .clone()方法深度 复制所有匹配的元素集合,包括所有匹配元素.匹配元素的下级元 ...