Disktra 看上去就像是prim和bellman_ford结合的算法。
同样是采取松弛的方法,不同的是bellman按顺序把边遍历了逐渐调整,而Diskstra是按邻接的结点(和prime算法里面是一样的)来遍历松弛的。有选择的去遍历边,代码的效率有所提高。如果用斐波那契堆实现最小优先队列去extract-min的话,运行时间能到O(VlgV+E)
#include "stdafx.h"
#include<stdio.h>
#define N 100
#define INF 0x3f3f3f3f
int map[N][N]; //储存weight的二维数组
int currentDistance[N]; //结点当前的distance,过一会可能就变了。这是用于作比较的数组
int parent[N]; //这个数组在我的程序里实际上是没用的,但是还是给他维护一下吧,这是正向的思维,寻找新的parent
bool visited[N];
int i, j, k;
int edgeNum; //边的条数
int vertexNum; //结点的个数
void Dijkstra(int s)
{
for (i = 0; i < N; i++) //初始化数组
{
currentDistance[i] = INF;
parent[i] = -1;
visited[i] = false;
}
currentDistance[s] = 0;
for (int p = 1; p <= vertexNum - 1; p++)
{ //进行N-1次循环,加入剩下的N-1个点
int t=INF, Min = INF;
for (int i = 0; i < N; i++)
if (!visited[i] && currentDistance[i] < Min) //如果没有访问过这个结点并且他的值小于min //寻找集合1-S中到集合S最近的点t
{
Min = currentDistance[i];
t = i; //最小值就变成他并且记录他的下标i
}
if (t != INF)
{
visited[t] = true; //找到那个当前的最小值之后,把标记他为已经访问,然后再把权值加到路径里面去
}
for(k=0;k<N;k++)
if (t!=INF && map[t][k] != INF)
{
if (currentDistance[k] > currentDistance[t] + map[t][k])
{
currentDistance[k] = currentDistance[t] + map[t][k];
parent[k] = t;
}
}
}
for (i = 0; i < N; i++) //输出路径
{
if (currentDistance[i] != INF)
printf("%d,(%d) ", i, currentDistance[i]);
}
}
int main()
{
int s;
printf("输入结点个数:\n");
scanf_s("%d", &vertexNum);
for (int i = 0; i < N; i++) //初始化矩阵为最大值
for (int j = 0; j < N; j++)
map[i][j] = INF;
printf("输入边的条数:\n");
scanf_s("%d", &edgeNum);
printf("输入源结点:\n");
scanf_s("%d", &s);
printf("输入两点和权重(逗号分隔)\n");
int a, b, c;
for (int i = 0; i<edgeNum; i++) {
scanf_s("%d,%d,%d", &a, &b, &c);
map[a][b] = c;
}
printf("单源最短路径:\n");
Dijkstra(s);
return 0;
}
用数组去写代码行数上看起来是少,但是模块化做得不好,而且在分析时间复杂度的时候会变得很不清晰。