Dijkstra 单源最短路径算法
Dijkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家 Edsger Dijkstra 于 1956 年构思并于 1959 年发表。其解决的问题是:给定图 G 和源顶点 v,找到从 v 至图中所有顶点的最短路径。

Dijkstra 算法采用贪心算法(Greedy Algorithm)范式进行设计。在最短路径问题中,对于带权有向图 G = (V, E),Dijkstra 算法的初始实现版本未使用最小优先队列实现,其时间复杂度为 O(V2),基于 Fibonacci heap 的最小优先队列实现版本,其时间复杂度为 O(E + VlogV)。

Bellman-Ford 算法和 Dijkstra 算法同为解决单源最短路径的算法。对于带权有向图 G = (V, E),Dijkstra 算法要求图 G 中边的权值均为非负,而 Bellman-Ford 算法能适应一般的情况(即存在负权边的情况)。一个实现的很好的 Dijkstra 算法比 Bellman-Ford 算法的运行时间 O(V*E) 要低。
Dijkstra 算法描述:
- 创建源顶点 v 到图中所有顶点的距离的集合 distSet,为图中的所有顶点指定一个距离值,初始均为 Infinite,源顶点距离为 0;
- 创建 SPT(Shortest Path Tree)集合 sptSet,用于存放包含在 SPT 中的顶点;
- 如果 sptSet 中并没有包含所有的顶点,则:
- 选中不包含在 sptSet 中的顶点 u,u 为当前 sptSet 中未确认的最短距离顶点;
- 将 u 包含进 sptSet;
- 更新 u 的所有邻接顶点的距离值;
伪码实现如下:
function Dijkstra(Graph, source):
dist[source] ← // Distance from source to source
prev[source] ← undefined // Previous node in optimal path initialization
for each vertex v in Graph: // Initialization
if v ≠ source // Where v has not yet been removed from Q (unvisited nodes)
dist[v] ← infinity // Unknown distance function from source to v
prev[v] ← undefined // Previous node in optimal path from source
end if
add v to Q // All nodes initially in Q (unvisited nodes)
end for
while Q is not empty:
u ← vertex in Q with min dist[u] // Source node in first case
remove u from Q
for each neighbor v of u: // where v has not yet been removed from Q.
alt ← dist[u] + length(u, v)
if alt < dist[v]: // A shorter path to v has been found
dist[v] ← alt
prev[v] ← u
end if
end for
end while
return dist[], prev[]
end function
例如,下面是一个包含 9 个顶点的图,每条边分别标识了距离。

源顶点 source = 0,初始时,
- sptSet = {false, false, false, false, false, false, false, false, false};
- distSet = {0, INF, INF, INF, INF, INF, INF, INF, INF};
将 0 包含至 sptSet 中;
- sptSet = {true, false, false, false, false, false, false, false, false};
更新 0 至其邻接节点的距离;
- distSet = {0, 4, INF, INF, INF, INF, INF, 8, INF};

选择不在 sptSet 中的 Min Distance 的顶点,为顶点 1,则将 1 包含至 sptSet;
- sptSet = {true, true, false, false, false, false, false, false, false};
更新 1 至其邻接节点的距离;
- distSet = {0, 4, 12, INF, INF, INF, INF, 8, INF};

选择不在 sptSet 中的 Min Distance 的顶点,为顶点 7,则将 7 包含至 sptSet;
- sptSet = {true, true, false, false, false, false, false, true, false};
更新 7 至其邻接节点的距离;
- distSet = {0, 4, 12, INF, INF, INF, 9, 8, 15};

选择不在 sptSet 中的 Min Distance 的顶点,为顶点 6,则将 6 包含至 sptSet;
- sptSet = {true, true, false, false, false, false, true, true, false};
更新 6 至其邻接节点的距离;
- distSet = {0, 4, 12, INF, INF, 11, 9, 8, 15};

以此类推,直到遍历结束。
- sptSet = {true, true, true, true, true, true, true, true, true};
- distSet = {0, 4, 12, 19, 21, 11, 9, 8, 14};

最终结果为源顶点 0 至所有顶点的距离:
Vertex Distance from Source
0 0
1 4
2 12
3 19
4 21
5 11
6 9
7 8
8 14
C#代码实现:
using System;
using System.Collections.Generic;
using System.Linq; namespace GraphAlgorithmTesting
{
class Program
{
static void Main(string[] args)
{
int[,] graph = new int[, ]
{
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , },
{, , , , , , , , }
}; Graph g = new Graph(graph.GetLength());
for (int i = ; i < graph.GetLength(); i++)
{
for (int j = ; j < graph.GetLength(); j++)
{
if (graph[i, j] > )
g.AddEdge(i, j, graph[i, j]);
}
} int[] dist = g.Dijkstra();
Console.WriteLine("Vertex\t\tDistance from Source");
for (int i = ; i < dist.Length; i++)
{
Console.WriteLine("{0}\t\t{1}", i, dist[i]);
} Console.ReadKey();
} class Edge
{
public Edge(int begin, int end, int distance)
{
this.Begin = begin;
this.End = end;
this.Distance = distance;
} public int Begin { get; private set; }
public int End { get; private set; }
public int Distance { get; private set; }
} class Graph
{
private Dictionary<int, List<Edge>> _adjacentEdges
= new Dictionary<int, List<Edge>>(); public Graph(int vertexCount)
{
this.VertexCount = vertexCount;
} public int VertexCount { get; private set; } public void AddEdge(int begin, int end, int distance)
{
if (!_adjacentEdges.ContainsKey(begin))
{
var edges = new List<Edge>();
_adjacentEdges.Add(begin, edges);
} _adjacentEdges[begin].Add(new Edge(begin, end, distance));
} public int[] Dijkstra(int source)
{
// dist[i] will hold the shortest distance from source to i
int[] distSet = new int[VertexCount]; // sptSet[i] will true if vertex i is included in shortest
// path tree or shortest distance from source to i is finalized
bool[] sptSet = new bool[VertexCount]; // initialize all distances as INFINITE and stpSet[] as false
for (int i = ; i < VertexCount; i++)
{
distSet[i] = int.MaxValue;
sptSet[i] = false;
} // distance of source vertex from itself is always 0
distSet[source] = ; // find shortest path for all vertices
for (int i = ; i < VertexCount - ; i++)
{
// pick the minimum distance vertex from the set of vertices not
// yet processed. u is always equal to source in first iteration.
int u = CalculateMinDistance(distSet, sptSet); // mark the picked vertex as processed
sptSet[u] = true; // update dist value of the adjacent vertices of the picked vertex.
for (int v = ; v < VertexCount; v++)
{
// update dist[v] only if is not in sptSet, there is an edge from
// u to v, and total weight of path from source to v through u is
// smaller than current value of dist[v]
if (!sptSet[v]
&& distSet[u] != int.MaxValue
&& _adjacentEdges[u].Exists(e => e.End == v))
{
int d = _adjacentEdges[u].Single(e => e.End == v).Distance;
if (distSet[u] + d < distSet[v])
{
distSet[v] = distSet[u] + d;
}
}
}
} return distSet;
} /// <summary>
/// A utility function to find the vertex with minimum distance value,
/// from the set of vertices not yet included in shortest path tree
/// </summary>
private int CalculateMinDistance(int[] distSet, bool[] sptSet)
{
int minDistance = int.MaxValue;
int minDistanceIndex = -; for (int v = ; v < VertexCount; v++)
{
if (!sptSet[v] && distSet[v] <= minDistance)
{
minDistance = distSet[v];
minDistanceIndex = v;
}
} return minDistanceIndex;
}
}
}
}
参考资料
- 广度优先搜索
- Dijkstra's algorithm
- Greedy Algorithms | Set 7 (Dijkstra’s shortest path algorithm)
- Bellman-Ford 单源最短路径算法
- Introduction to Algorithms 6.006 - Lecture 16
本篇文章《Dijkstra 单源最短路径算法》由 Dennis Gao 发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。
Dijkstra 单源最短路径算法的更多相关文章
- 【模板 && 拓扑】 Dijkstra 单源最短路径算法
话不多说上代码 链式前向星233 #include<bits/stdc++.h> using namespace std; ,_max=0x3fffffff; //链式前向星 struct ...
- Bellman-Ford 单源最短路径算法
Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 Richard Bellman 和 Leste ...
- Dijkstra——单源最短路径
算法思想 ①从一个源点开始,找距离它最近的点顶点v ②然后以顶点v为起点,去找v能到达的顶点w,即v的邻居 比较源点直接到 v的距离和(源点到v的距离+v到w的距离) 若大于后者则更新源点的到w的开销 ...
- 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(二)
一.基于邻接表的Dijkstra算法 如前一篇文章所述,在 Dijkstra 的算法中,维护了两组,一组包含已经包含在最短路径树中的顶点列表,另一组包含尚未包含的顶点.使用邻接表表示,可以使用 BFS ...
- 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(一)
一.算法介绍 迪杰斯特拉算法(英语:Dijkstra's algorithm)由荷兰计算机科学家艾兹赫尔·迪杰斯特拉在1956年提出.迪杰斯特拉算法使用了广度优先搜索解决赋权有向图的单源最短路径问题. ...
- 经典贪心算法(哈夫曼算法,Dijstra单源最短路径算法,最小费用最大流)
哈夫曼编码与哈夫曼算法 哈弗曼编码的目的是,如何用更短的bit来编码数据. 通过变长编码压缩编码长度.我们知道普通的编码都是定长的,比如常用的ASCII编码,每个字符都是8个bit.但在很多情况下,数 ...
- 单源最短路径算法---Dijkstra
Dijkstra算法树解决有向图G=(V,E)上带权的单源最短路径问题,但是要求所有边的权值非负. 解题思路: V表示有向图的所有顶点集合,S表示那么一些顶点结合,从源点s到该集合中的顶点的最终最短路 ...
- Dijkstra算法详细(单源最短路径算法)
介绍 对于dijkstra算法,很多人可能感觉熟悉而又陌生,可能大部分人比较了解bfs和dfs,而对dijkstra和floyd算法可能知道大概是图论中的某个算法,但是可能不清楚其中的作用和原理,又或 ...
- Dijkstra单源最短路径,POJ(2387)
题目链接:http://poj.org/problem?id=2387 Dijkstra算法: //求某一点(源点)到另一点的最短路,算法其实也和源点到所有点的时间复杂度一样,O(n^2); 图G(V ...
随机推荐
- .net点选验证码实现思路分享
哈哈好久没冒泡了,最进看见点选验证码有点意思,所以想自己写一个. 先上效果图 如果你被这个效果吸引了就请继续看下去. 贴代码前先说点思路: 1.要有一个汉字库,并按字形分类.(我在数据库里是安部首分类 ...
- javascript动画系列第三篇——碰撞检测
前面的话 前面分别介绍了拖拽模拟和磁性吸附,当可视区域内存在多个可拖拽元素,就出现碰撞检测的问题,这也是javascript动画的一个经典问题.本篇将详细介绍碰撞检测 原理介绍 碰撞检测的方法有很多, ...
- html5标签canvas函数drawImage使用方法
html5中标签canvas,函数drawImage(): 使用drawImage()方法绘制图像.绘图环境提供了该方法的三个不同版本.参数传递三种形式: drawImage(image,x,y):在 ...
- 由js apply与call方法想到的js数据类型(原始类型和引用类型)
原文地址:由js apply与call方法想到的js数据类型(原始类型和引用类型) js的call方法与apply方法的区别在于第二个参数的不同,他们都有2个参数,第一个为对象(即需要用对象a继承b, ...
- Hadoop学习之旅二:HDFS
本文基于Hadoop1.X 概述 分布式文件系统主要用来解决如下几个问题: 读写大文件 加速运算 对于某些体积巨大的文件,比如其大小超过了计算机文件系统所能存放的最大限制或者是其大小甚至超过了计算机整 ...
- 敏捷测试模式之Scrum及其实践
一. 敏捷开发模式简介 敏捷是近年来软件研发领域很火的一个词,采用敏捷开发模式的研发团队是越来越多了,尤其是敏捷模式中的Scrum更是佼佼者大行其道,这表明敏捷模式确有其好处,能给企业带来效率的 ...
- SQLServer如何添加try catch
在.net中我们经常用到try catch.不过在sqlserver中我们也可以使用try catch捕捉错误,在这里把语法记录下来和大家分享一下, --构建存储过程CREATE PROCEDURE ...
- Linux:将rhel yum 切换到centos yum
Red Hat Enterprise Linux Server(RHEL) yum安装软件时This system is not registered with RHN. RHN support wi ...
- POJ1149 PIGS [最大流 建图]
PIGS Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 20662 Accepted: 9435 Description ...
- asp.net中ashx生成验证码代码放在Linux(centos)主机上访问时无法显示问题
最近有个项目加入了验证码功能,就从自己博客以前的代码中找到直接使用,直接访问验证码页面报错如下: 源代码:asp.net中使用一般处理程序生成验证码 Application Exception Sys ...