Dijkstra算法简单介绍
Dijkstra算法解决的是带权重的有向图上单源最短路径问题,该算法要求所有边的权重都为非负值。Dijkstra算法可以用于单个源点与单个目的点之间的最短路径问题,也可以用于单个源点和多个目的点之间的最短路径问题,在后者,该算法将生成一个“最短路径树”。没有使用最小优先队列的Dijkstra算法的时间复杂度为 O(|V|2) ,而后来相继有使用最小优先队列、二叉堆、d堆和 Fibonacci 堆等算法,很大程度上降低了时间复杂度。本文只讲述原始的Dijkstra算法和使用最小优先队列的Dijkstra算法。
The algorithm exists in many variants; Dijkstra’s original variant found the shortest path between two nodes, but a more common variant fixes a single node as the “source” node and finds shortest paths from the source to all other nodes in the graph, producing a shortest-path tree.
Dijkstra’s original algorithm does not use a min-priority queue and runs in time {\displaystyle O(|V|^{2})} O(|V|^{2}) (where {\displaystyle |V|} |V| is the number of nodes). The idea of this algorithm is also given in Leyzorek et al. 1957. The implementation based on a min-priority queue implemented by a Fibonacci heap and running in {\displaystyle O(|E|+|V|\log |V|)} O(|E|+|V|\log |V|) (where {\displaystyle |E|} |E| is the number of edges) is due to Fredman & Tarjan 1984. This is asymptotically the fastest known single-source shortest-path algorithm for arbitrary directed graphs with unbounded non-negative weights. However, specialized cases (such as bounded/integer weights, directed acyclic graphs etc.) can indeed be improved further as detailed in § Specialized variants. —— from WIKIPEDIA
1. 伪代码
In the following algorithm, the code u ← vertex in Q with min dist[u], searches for the vertex u in the vertex set Q that has the least dist[u] value. length(u, v) returns the length of the edge joining (i.e. the distance between) the two neighbor-nodes u and v. The variable alt on line 17 is the length of the path from the root node to the neighbor node v if it were to go through u. If this path is shorter than the current shortest path recorded for v, that current path is replaced with this alt path. The prev array is populated with a pointer to the “next-hop” node on the source graph to get the shortest route to the source. —— from WIKIPEDIA
function Dijkstra(Graph, source):
create vertex set Q
for each vertex v in Graph: // Initialization
dist[v] ← INFINITY // Unknown distance from source to v
prev[v] ← UNDEFINED // Previous node in optimal path from source
add v to Q // All nodes initially in Q (unvisited nodes)
dist[source] ← 0 // Distance from source to source
while Q is not empty:
u ← vertex in Q with min dist[u] // Node with the least distance will be selected first
remove u from Q
for each neighbor v of u: // where v is still in 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
return dist[], prev[]
如果需要找到到源点和某点
v
之间的最短路径,只要在上述的最短路径树上根据前驱结点回溯即可,即找到
S ← empty sequence
u ← target
while prev[u] is defined: // Construct the shortest path with a stack S
insert u at the beginning of S // Push the vertex onto the stack
u ← prev[u] // Traverse from target to source
insert u at the beginning of S // Push the source onto the stack
使用最小优先队列
A min-priority queue is an abstract data type that provides 3 basic operations : add_with_priority(), decrease_priority() and extract_min(). As mentioned earlier, using such a data structure can lead to faster computing times than using a basic queue. Notably, Fibonacci heap (Fredman & Tarjan 1984) or Brodal queue offer optimal implementations for those 3 operations. As the algorithm is slightly different, we mention it here, in pseudo-code as well —— form WIKIPEDIA
function Dijkstra(Graph, source):
dist[source] ← 0 // Initialization
create vertex set Q
for each vertex v in Graph:
if v ≠ source
dist[v] ← INFINITY // Unknown distance from source v
prev[v] ← UNDEFINED // Predecessor of v
Q.add_with_priority(v, dist[v])
while Q is not empty: // The main loop
u ← Q.extract_min() // Remove and return best vertex
for each neighbor v of u: // only v that is still in Q
alt ← dist[u] + length(u, v)
if alt < dist[v]
dist[v] ← alt
prev[v] ← u
Q.decrease_priority(v, alt)
return dist[], prev[]