戴克斯特拉算法

戴克斯特拉算法（Dijkstra's algorithm），又称迪杰斯特拉算法、Dijkstra算法，是由荷兰计算机科学家艾兹赫尔·戴克斯特拉在1956年发现的算法，并于3年后在期刊上发表。戴克斯特拉算法使用类似广度优先搜索的方法解决赋权图的单源最短路径问题。
该算法存在很多变体：戴克斯特拉的原始版本仅适用于找到两个顶点之间的最短路径，后来更常见的变体固定了一个顶点作为源结点然后找到该顶点到图中所有其它结点的最短路径，产生一个最短路径树。
该算法解决了图 formula_1上带权的单源最短路径问题。具体来说，戴克斯特拉算法设置了一顶点集合formula_2，在集合formula_2中所有的顶点与源点formula_4之间的最终最短路径权值均已确定。算法反复选择最短路径估计最小的点formula_5并将formula_6加入formula_2中。该算法常用于路由算法或者作为其他图算法的一个子模块。举例来说，如果图中的顶点表示城市，而边上的权重表示城市间开车行经的距离，该演算法可以用来找到两个城市之间的最短路径。
应当注意，绝大多数的戴克斯特拉算法不能有效处理带有负权边的图。
戴克斯特拉算法在计算机科学的人工智能等领域也被称为均一开销搜索，并被认为是的一个特例。
描述.
戴克斯特拉算法通过保留目前为止所找到的每个顶点formula_8从formula_4到formula_10的最短路径来工作。初始时，原点formula_4的路径权重被赋为 0 （即原点的实际最短路径=0）。同时把所有其他顶点的路径长度设为无穷大，即表示我们不知道任何通向这些顶点的路径。当算法结束时，formula_12 中储存的便是从formula_4到formula_10的最短路径，或者如果路径不存在的话是无穷大。
松弛操作是戴克斯特拉算法的基础操作：如果存在一条从formula_6到formula_10的边，那么从formula_4到formula_10的一条新路径是将边formula_19添加到从formula_4到formula_6的路径尾部来拓展一条从formula_4到formula_10的路径。这条路径的长度是formula_24。如果这个值比目前已知的formula_25的值要小，那么可以用这个值来替代当前<math>dname=IntroToAlgo />。松弛边的操作一直执行到所有的formula_25都代表从formula_4到formula_10的最短路径的长度值。
算法维护两个顶点集合formula_2和formula_30。集合formula_2保留所有已知实际最短路径值的顶点，而集合formula_30则保留其他所有顶点。集合formula_2初始状态为空，而后每一步都有一个顶点从formula_30移动到formula_2。这个被选择的顶点是formula_30中拥有最小的formula_12值的顶点。当一个顶点formula_6从formula_30中转移到了formula_2中，算法对formula_6的每条外接边formula_42进行松弛。
《算法导论》中给出了以下伪代码：该伪代码计算并保留图formula_43中原点formula_4到每一顶点formula_10的最短距离formula_12。其中，函数formula_47将顶点集合formula_30中有最小formula_12值的顶点formula_6从formula_30中删除并返回formula_6。
如果我们只对在formula_4和formula_66之间寻找一条最短路径的话，我们可以在第5或第6行添加条件如果满足formula_67的话终止程序。
在肯尼·罗森所著的《离散数学及其应用》中给出了如下的另一份伪代码：
在该 算法演示页面 ，可以自定义节点，边的权重等信息，然后观察算法每一步的执行过程。
时间复杂度.
我们可以用大O符号将该算法的运行时间表示为边数formula_84和顶点数formula_85的函数。
对于任何基于顶点集formula_30的实现，算法的运行时间是formula_87，其中formula_88和formula_89分别表示完成键的降序排列时间和从formula_30中提取最小键值的时间。
对于没有任何优化的戴克斯特拉算法，实际上等价于每次遍历了整个图的所有结点来找到Q中满足条件的元素（即寻找最小的顶点是formula_91的），此外实际上还需要遍历所有的边一遍，因此算法的复杂度是formula_92。
对于边数少于formula_93的稀疏图来说，可以用邻接表来更有效的实现该算法。
可以使用一个二叉堆或者斐波纳契堆用作优先队列来寻找最小的顶点（formula_94）以优化算法。当用到二叉堆的时候，算法所需的时间为formula_95，斐波纳契堆能提高一些性能，让算法运行时间达到formula_96。然而，使用斐波纳契堆进行编程，有时会由于算法常数过大而导致速度没有显著提高。
下面是一些戴克斯特拉算法经典实现的复杂度比较：
正确性证明.
戴克斯特拉本人在他的论文中给出了一份简单的证明。
《算法导论》使用循环不变式（数学归纳法）给出了如下的一份证明：
起源与历史.
戴克斯特拉1956年在荷兰数学和计算机科学研究学会担任程序员时为了展示新型计算机ARMAC的功能曾思考过最短路径问题的解法。他的目标是让不去实际计算的人也能理解这个问题和解决的方法，于是他在发现了这个算法之后在ARMAC上做了简单实验。1959年，他正式将此算法发表在期刊上，该算法也成为了戴克斯特拉成名的基石之一。
相关应用.
中需要计算最短路时常常要用到该算法，该算法在开放最短路径优先和中间系统到中间系统协议中的相关应用是其在网络路由中的典型实现。
戴克斯特拉算法及其改进算法应用广泛，尤其是在寻路、交通、规划中。
如果有已知信息可用来估计某一点到目标点的距离，则可改用A*搜寻算法，以减小最短路径的搜索范围，戴克斯特拉算法本身也可以看作是A*搜索算法的一个特例。
戴克斯特拉算法本身采用了与Prim算法类似的贪心策略。快速行进算法与戴克斯特拉算法同样有相似之处。
参考源程序.
以下是该算法使用堆优化的一个C++实现参考：
<syntaxhighlight lang="c++" line="1">
// 无向图
using namespace std;
// iPair ==> Integer Pair（整数对）
typedef pair<int, int> iPair;
// 加边
void addEdge(vector<pair<int, intÂ» adj[], int u, int v, int wt)
// 计算最短路
void shortestPath(vector<pair<int, intÂ» adj[], int V, int src)
int main()
</syntaxhighlight>
以下是该算法Python的一个实现：
<syntaxhighlight lang="python" line="1">
import sys
max = sys.maxsize
vertices_number = 6
adjacency_matrix = [
start = []
dest = ["2", "5"]
key = []
def init_keys(s: int):
def dijkstra(from_vertex, dest_vertex):
def find_shortest_router():
def main():
if __name__ == '__main__':
</syntaxhighlight>