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 ...
随机推荐
- [APUE]文件和目录(中)
一.link.unlink.remove和rename 一个文件可以有多个目录项指向其i节点.使用link函数可以创建一个指向现存文件连接 #include <unistd.h> int ...
- .NET中AOP方便之神SheepAspect
SheepAspect 简介以及代码示列: SheepAspect是一个AOP框架为.NET平台,深受AspectJ.它静织目标组件作为一个编译后的任务(编译时把AOP代码植入). 多有特性时,可根据 ...
- Entity Framework的启动速度优化
最近开发的服务放到IIS上寄宿之后,遇到一些现象,比如刚部署之后,第一次启动很慢:程序放置一会儿,再次请求也会比较慢.比如第一个问题,可以解释为初次请求某一个服务的时候,需要把程序集加载到内存中可能比 ...
- “老坛泡新菜”:SOD MVVM框架,让WinForms焕发新春
火热的MVVM框架 最近几年最热门的技术之一就是前端技术了,各种前端框架,前端标准和前端设计风格层出不穷,而在众多前端框架中具有MVC,MVVM功能的框架成为耀眼新星,比如GitHub关注度很高的Vu ...
- iOS之延时执行(睡眠)的几种方法
1. 最直接的方法: [self performSelector:@selector(deleyMethod) withObject:nil afterDelay:1.0]; 此方式要求必须在主线程中 ...
- listview下拉刷新和上拉加载更多的多种实现方案
listview经常结合下来刷新和上拉加载更多使用,本文总结了三种常用到的方案分别作出说明. 方案一:添加头布局和脚布局 android系统为listview提供了addfootview ...
- Atitit 解决Unhandled event loop exception错误的办法
Atitit 解决Unhandled event loop exception错误的办法 查看workspace/.metadata/.log org.eclipse.swt.SWTError: No ...
- sql 删除表中的重复记录
嗯,遇见了表中存在重复的记录的问题,直接写sql删除时最快的,才不要慢慢的复制到excel表中慢慢的人工找呢.哼. 如下sql,找出重复的记录,和重复记录中ID值最小的记录(表中ID为自增长) sel ...
- OpenGL shader 中关于顶点坐标值的思考
今天工作中需要做一个事情: 在shader内部做一些空间距离上的计算,而且需要对所有的点进行计算,符合条件的显示,不符合条件的点不显示. 思路很简单,在vertex shader内知道顶点坐标,进行计 ...
- BZOJ 1597: [Usaco2008 Mar]土地购买 [斜率优化DP]
1597: [Usaco2008 Mar]土地购买 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4026 Solved: 1473[Submit] ...