给定一个有向图G和起点S,如何求出图中S到其中所有点的最短路径呢?Dijkstra给出了一个比较好的算法,它的基本步骤如下:
1.计算起点s到所有节点的距离。
2.挑出其中距离最小的节点smin。(如果这个节点已经被调过了,就不再选它了)
3.利用这个节点更新起点到其他节点的最小距离:如果s到smin的直接距离+smin到其他节点某个节点的直接距离 < s到其他某个节点的直接距离,那么就用s到smin的直接距离+smin到其他某个节点的直接距离代替s到其他某个节点的直接距离。
4.不断重复2、3直到只剩下一个节点。
为了实现上述功能,我特意在图的数据结构中加入两个数组:hasUsed表示这个节点是否被使用,而length记录了起点到各个节点的距离:
#include <stdio.h>
#include <malloc.h>
#include <limits.h>
typedef int** ADJACENTMATRIX;
typedef struct directedAcyclineGraph
{
ADJACENTMATRIX matrix;
int vertexNumber;
int arcNumber;
char* vertex;
bool* hasUsed;
//记录起点到每个节点的距离
int* length;
}DAG;
#define MAX 8
//基本操作
//初始化
DAG initGraph(int);
//销毁
void destroyGraph(DAG* );
//添加
bool addArc(DAG* ,char,char,int);
//删除
bool deleteArc(DAG* ,char,char);
//打印邻接矩阵
void printGraph(DAG* );
//Dijkstra算法相关函数
void initLengthVector(DAG* ,int );
int selectShortestLengthNode(DAG* );
void Dijkstra(DAG* ,char );
DAG initGraph(int n)
{
DAG g;
g.vertexNumber = n;
g.arcNumber = 0;
g.vertex = (char*)malloc(sizeof(char) * n);
g.hasUsed = (bool*)malloc(sizeof(bool) * n);
g.length = (int*)malloc(sizeof(int) * n);
char start = 'A';
for(int i = 0; i < n;++i)
{
g.vertex[i] = start + i;
g.hasUsed[i] = false;
g.length[i] = INT_MAX;
}
g.matrix = (int**)malloc(sizeof(int*) * n);
for(int i = 0; i < n;++i)
g.matrix[i] = (int*)malloc(sizeof(int) * n);
//邻接矩阵的初始为为最大值
for(int i = 0; i < n;++i)
for(int j = 0; j < n;++j)
g.matrix[i][j] = INT_MAX;
return g;
}
void destroyGraph(DAG* g)
{
free(g->vertex);
free(g->hasUsed);
free(g->length);
g->vertex = NULL;
g->hasUsed = NULL;
g->length = NULL;
for(int i = 0; i < g->vertexNumber;++i)
free(g->matrix[i]);
free(g->matrix);
g->matrix = NULL;
g->arcNumber = -1;
g->vertexNumber = -1;
}
bool addArc(DAG* g,char start,char end,int w)
{
int i = start - 'A';
int j = end - 'A';
if(i < 0 || i > g->vertexNumber || j < 0 || j > g->vertexNumber)
{
printf("vertexes does not exsist!\n");
return false;
}
else
{
g->matrix[i][j] = w;
g->arcNumber++;
return true;
}
}
bool deleteArc(DAG* g,char start,char end)
{
int i = start - 'A';
int j = end - 'A';
if(i < 0 || i > g->vertexNumber || j < 0 || j > g->vertexNumber)
{
printf("vertexes does not exsist!\n");
return false;
}
if(INT_MAX == g->matrix[i][j] )
{
printf("there is no arc between vertexes!\n");
return false;
}
else
{
g->matrix[i][j] = INT_MAX;
g->arcNumber--;
return true;
}
}
void printGraph(DAG* g)
{
printf(" ");
for(int i = 0 ; i < g->vertexNumber;++i)
printf("%-4c ",g->vertex[i]);
for(int i = 0; i < g->vertexNumber;++i)
{
printf("\n");
printf("%-4c ",g->vertex[i]);
for(int j = 0; j < g->vertexNumber;++j)
{
if(INT_MAX == g->matrix[i][j] )
printf("NULL ");
else
printf("%-4d ",g->matrix[i][j]);
}
}
printf("\n");
}
//程序的工作是计算起始点到所有节点的最短距离
//并输出路径
void Dijkstra(DAG* g,char Start)
{
int start = Start - 'A';
g->hasUsed[start] = true;
int cnt = g->vertexNumber;
//初始化距离长度数组
initLengthVector(g,start);
while(cnt > 1)
{
int miniNode = selectShortestLengthNode(g);
// printf("挑出的节点为%d\n",miniNode);
//更新length数组
for(int i = 0; i < g->vertexNumber;++i)
{
if(i == start || i == miniNode)
continue;
//计算原路径长度和使用新增加一个节点作为过渡节点后的长度
if(g->length[i] > g->length[miniNode] + g->matrix[miniNode][i])
{
//注意:INT_MAX = 2147483647
//2147483647 > 2147483647+10因为2147483647+10为一个负数
if(INT_MAX == g->matrix[miniNode][i] || INT_MAX == g->length[miniNode])
;//什么也不做
else
g->length[i] = g->length[miniNode] + g->matrix[miniNode][i];
}
}
--cnt;
}
//输出到各个节点的长度
for(int i = 0; i < g->vertexNumber;++i)
{
if(start == i)
continue;
if(INT_MAX == g->length[i])
printf("节点%c不可到达\n",g->vertex[i]);
else
printf("到节点%c距离为:%d\n",g->vertex[i],g->length[i]);
}
}
void initLengthVector(DAG* g,int start)
{
for(int i = 0; i < g->vertexNumber;++i)
{
if(i == start)
continue;
g->length[i] = g->matrix[start][i];
}
}
int selectShortestLengthNode(DAG* g)
{
int shortestPath = INT_MAX;
int vertex = 0;
for(int i = 0; i < g->vertexNumber;++i)
{
if(true == g->hasUsed[i] )
continue;
if(shortestPath > g->length[i])
{
shortestPath = g->length[i];
vertex = i;
}
}
g->hasUsed[vertex] = true;
return vertex;
}
程序中还有一定需要注意的是,因为INT_MAX = 2147483647,所以INT_MAX加上一个数会发生越界的情况,导致值为负数,这是我们不想出现的情况,需要避免。