最短路径与Dijkstra算法

来源:互联网 发布:手机无法安装软件 编辑:程序博客网 时间:2024/06/12 00:43

给定一个有向图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 ");elseprintf("%-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]);//什么也不做elseg->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]);elseprintf("到节点%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加上一个数会发生越界的情况,导致值为负数,这是我们不想出现的情况,需要避免。