Dijkstra
该算法是最近备考研时,学到图中Dijkstra算法时,自己用
C实现的代码,代码可以直接运行。
说明:
-
图是由邻接表存储的
#include<stdio.h> #include<malloc.h> #include<stdlib.h> #include<limits.h> #define MaxVertexNum 100 #define INFINITY INT_MAX //最大值 //用邻接表定义图 //定义边或弧 typedef struct ArcNode{ int adjvex;//边或弧指向哪个结点 int info;//边或弧的权值 struct ArcNode *next;//执行下一条弧的指针 }ArcNode; //定义顶点 typedef struct VNode{ int data;//顶点信息 ArcNode *first;//第一条边/弧 }VNode,AdjList[MaxVertexNum]; //用邻接表存储图 typedef struct{ AdjList vertices;//顶点数组 int vexnum,arcnum;//图的当前顶点数和弧数 }ALGraph; //初始化图 void InitGraph(ALGraph &G,int n){ G.vexnum = 0; G.arcnum = 0; //分配头结点 int i; for (i=1;i<=n;i++){ G.vertices[i].first = (ArcNode *)malloc(sizeof(ArcNode)); G.vertices[i].first->next = NULL; } } //存储图 void StoreGraph(ALGraph &G,int n,int m,int data2[][3]){//n是顶点个数,m是边的条数 //初始化 InitGraph(G,n); //存储每个结点的信息 int i; for (i=1;i<=n;i++){ G.vertices[i].data = i; G.vexnum++; } //各个结点的关系,遍历边 for (i=0;i<m;i++){ ArcNode* arcNode = (ArcNode *)malloc(sizeof(ArcNode)); arcNode->adjvex = data2[i][1];//边或弧指向的结点 arcNode->info = data2[i][2];//边或弧的权值 //第一次插入 if (G.vertices[data2[i][0]].first->next == NULL){ G.vertices[data2[i][0]].first->next = arcNode; arcNode->next = NULL; }else{//非第一次插入 //从头结点插入边或弧 ArcNode* arcNext = G.vertices[data2[i][0]].first->next; G.vertices[data2[i][0]].first->next = arcNode; arcNode->next = arcNext; } G.arcnum++;//增加一条弧 } } //打印邻接表 void print(ALGraph G){ int i; int data = 0; int info; for (i=1;i<=G.vexnum;i++){ ArcNode* p = G.vertices[i].first->next; printf("%d",i); while (p!=NULL){ data = p->adjvex; info = p->info; printf("--%d-->%d",info,data); p = p->next; } printf("\n"); } } /* 初始化Dijkstra 把顶点v到各顶点的路径长度记录到dist[]中,并记录前驱结点 */ void InitDijkstra(ALGraph G,int v,int dist[],int path[],bool final[]){ int i; //将所有值赋为无穷 for (i=1;i<=G.vexnum;i++){ final[i] = false; dist[i] = INT_MAX; } dist[v] = 0; final[v] = true; ArcNode* p = G.vertices[v].first->next; while (p!=NULL){ i = p->adjvex;//结点下标 dist[i] = p->info;//从<v-i>的权值 path[i] = v; p = p->next; } } //从dist[]中找到最小值,不包括已经找到的值 int MinDist(int dist[],bool final[],int n){ int min = INT_MAX; int i; for(i=1;i<=n;i++){ if(!final[i] && dist[i]<min){ min = i; } } return min; } /* Dijkstra算法:寻找一个结点到其他各结点的单元路径--时间复杂度O(V2),因为需要找到MinDist()需要一定时间 v:是目标顶点 final[]:是标记各顶点是否已找到最短路径,下标从1开始 dist[]: 是记录目标顶点到各顶点的最短路径 ,下标从1开始 path[]:是记录路径上的前驱结点 ,下标从1开始 n:结点数 */ void Dijkstra(ALGraph G,int v,bool final[],int dist[],int path[],int n){ //初始化 InitDijkstra(G,v,dist,path,final); int count = 0;//记录找到几个最短路径了 //遍历还未找到最短路径的结点 while (count<G.vexnum-2){//这里-2不容易理解 //从dist中找到最短路径,这里运用贪心的思想 int index = MinDist(dist,final,n); final[index] = true; count++; //更新dist中的值 ArcNode *p = G.vertices[index].first->next; while (p!=NULL){ int v2 = p->adjvex; int v2Info = p->info; int v2Dist = dist[index]+v2Info; if (v2Dist < dist[v2]){ dist[v2] = v2Dist; } p = p->next; } } } void printDist(int dist[],int n){ int i; for (i=1;i<=n;i++){ printf("%d ",dist[i]); } } //主函数 int main(void){ //这不是指针,是一个结构体变量,cpu会自动给它分配内存, //如果是结构体指针,则必须手动malloc给它分配内存 ALGraph G; int n = 5; int m = 7; int data[][3] = { {1,2,2},{1,4,5},{2,3,10},{2,4,6}, {3,5,6},{4,3,3},{4,5,9} }; StoreGraph(G,n,m,data); print(G); printf("\n"); bool final[n+1]; int dist[n+1]; int path[n+1]; int v = 2; Dijkstra(G,v,final,dist,path,n); printDist(dist,n); printf("\nending progarm"); return 0; }
运行结果:
说明:
1--5-->4表示顶点1到顶点4有边,且权值为5