Dijkstra算法 Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,是广度优先算法的一种,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。其基本原理是:每次新扩展一个距离最短的点,更新与其相邻的点的距离。当所有边权都为正时,由于不会存在一个距离更短的没扩展过的点,所以这个点的距离永远不会再被改变,因而保证了算法的正确性。不过根据这个原理,用Dijkstra求最短路的图不能有负权边,因为扩展到负权边的时候会产生更短的距离,有可能就破坏了已经更新的点距离不会改变的性质。 Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。 Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。
Dijkstra 算法的时间复杂度为O(n^2) 空间复杂度取决于存储方式,邻接矩阵为O(n^2)
先上代码:
// Dijkstra.cpp : 定义控制台应用程序的入口点。
//
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace::std;
#define INF 0x7fffffff
#define maxN 50
#pragma warning(disable:4996)
#define USE_C 1
#define NOT_USE_C 0
#define USE_CPP 1
int matrix[maxN][maxN];
// C++实现
void Dijkstra_cpp(vector<vector<int>>&vec, vector<int>& result, int v0){
vector<int> visited(vec.size(), 0); // 表示顶点是否被选中,0:顶点未被选中;1:顶点已被选中
int last_visited = 0;
visited[v0] = 1; // 选中起始顶点
result[0] = 0;
for (int i = 0; i < vec.size() - 1; ++i) { // N 个顶点需要做 N - 1 次循环
// 查看顶点周围的所有点
for (int j = 0; j < vec.size(); ++j) { // 循环遍历所有顶点
if (visited[j] == 0){ // 保证被查看的新顶点没有被访问到
if (vec[v0][j] != 0){ // 保证当前顶点(V0)与新顶点(j)之间有路径
int dist = vec[v0][j] + last_visited; // 计算 V0 到 J 的路径距离
if (dist < result[j])result[j] = dist; // 用新路径代替原来的路径
}
}
}
// 找出最小值
int minIndex = 0;
while (visited[minIndex] == 1) minIndex++; // 找第一个没有被选中的节点
for (int j = minIndex; j < vec.size(); ++j) {
if (visited[j] == 0 && result[j] < result[minIndex]){
minIndex = j;
}
}
last_visited = result[minIndex]; // 更新最小值
visited[minIndex] = 1; // 将最小值顶点选中
v0 = minIndex; // 下次查找从最限制顶点开始
}
}
// C语言实现
void Dijkstra_c(int out[], int N, int v0){
int i, j;
int visited[maxN] = { 0 }; // 表示顶点是否被选中,0:顶点未被选中;1:顶点已被选中
int last_visited = 0;
for (i = 0; i < N; ++i){
out[i] = INF; // 把输出结果全部初始化为无穷大
}
visited[v0] = 1; // 选中起始顶点
out[v0] = 0;
for (i = 0; i < N - 1; ++i) { // N 个顶点需要做 N - 1 次循环
// 查看顶点周围的所有点
for (j = 0; j < N; ++j) { // 循环遍历所有顶点
if (visited[j] == 0) { // 保证被查看的新顶点没有被访问到
if (matrix[v0][j] != 0){ // 保证当前顶点(V0)与新顶点(j)之间有路径
int dist = matrix[v0][j] + last_visited; // 计算 V0 到 J 的路径距离
if (dist < out[j])out[j] = dist; // 用新路径代替原来的路径
}
}
}
// 找出最小值
int minIndex = 0;
while (visited[minIndex] == 1) minIndex++; // 找第一个没有被选中的节点
for (j = minIndex; j < N; ++j) {
if (visited[j] == 0 && out[j] < out[minIndex]){
minIndex = j;
}
}
last_visited = out[minIndex]; // 更新最小值
visited[minIndex] = 1; // 将最小值顶点选中
v0 = minIndex; // 下次查找从最限制顶点开始
}
}
int _tmain(int argc, _TCHAR* argv[])
{
#if 0
freopen("Dijkstra2Data.txt", "r", stdin);
int result[maxN];
int N, i, j;
scanf("%d", &N);
for (i = 0; i < N; ++i){
for (j = 0; j < N; ++j){
scanf("%d", &matrix[i][j]);
}
}
Dijkstra_c(result, N, 0);
for (i = 0; i < N; ++i){
if (result[i] == INF)printf("INF\n");
else printf("%d\n", result[i]);
}
#endif
freopen("Dijkstra2Data.txt", "r", stdin);
int n;
scanf("%d", &n);
vector<vector<int>> vec(n, vector<int>(n, 0));
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; ++j){
cin >> vec[i][j];
}
}
vector<int> result(n, INF); // 把输出结果全部初始化为无穷大
Dijkstra_cpp(vec,result, 0);
for (int i = 0; i < n; ++i){
if (result[i] == INF)printf("INF\n");
else printf("%d\n", result[i]);
}
return 0;
}
假设我们的测试用例如下图所示:
我们以A作为起始顶点,计算A到每个顶点的最短路径,注意,这是一幅带权图,图的邻接矩阵表示如下:
计算结果如下: