1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "Dijkstra.h"
5
6 int g_node_num;/*用于计算实际节点数的全局变量*/
7 /****************************************
8 *函数名:InitGraphic
9 *参数:path-图的信息文件路径;arr-储存图的数组;nsize-数组大小
10 *返回值:BOOL-成功返回1,错误返回0
11 *说明:根据图的信息文件,初始化数组
12 *****************************************/
13 BOOL InitGraphic(char path[], node arr[], UINT nsize)
14 {
15 char buf[MAX_STRLEN];
16 char *pos;
17 char ctemp;
18 int ncost;
19 int i;
20 UINT nid;//临时顶点ID
21 UINT ncid;//临时连接顶点的ID
22 UINT nlinkpos;//连接顶点数组中的位置
23
24 memset(arr, 0, sizeof(node)*nsize);//赋值0
25 FILE *pfile = fopen(path, "r");
26 if(NULL == pfile) {
27 printf("Error opening file.\n");
28 return FALSE;
29 }
30 while(NULL != fgets(buf, MAX_STRLEN, pfile)) {
31 pos = strtok(buf, ":");//读取一行,解析第一个冒号之前的标号,即第几个节点
32 nid = atoi(pos);
33 if(nid < nsize) {
34 arr[nid-1].nID = nid;
35 arr[nid-1].pVer = (vertex*)malloc(sizeof(vertex));//申请一个顶点struct
36 if(NULL == arr[nid-1].pVer) {
37 printf("out of memory!\n");
38 return FALSE;
39 }
40 memset(arr[nid-1].pVer, 0, sizeof(vertex));//赋值0
41 arr[nid-1].pVer->id = nid;
42 g_node_num++;//节点数加1
43 } else {
44 fprintf(stderr, "access the boundary of setting:%d\n", nid);
45 }
46 }
47 rewind(pfile);//文件指针跳转到开始处,读取各顶点的相邻节点
48 for(i=0; i<g_node_num; i++) {
49 fscanf(pfile, "%d", &nid);//读取第一个节点标号
50 nlinkpos = 0;//指示其相邻节点结构体的当前位置
51 while((ctemp=fgetc(pfile)) != ';') {
52 fscanf(pfile, "%u-%d", &ncid, &ncost);
53 if(ncid > nsize || ncost < 0) {
54 fprintf(stderr, "access the boundary of setting or find negative cost:%u-%d\n", ncid, ncost);
55 return FALSE;
56 }
57
58 arr[nid-1].pVer->pLinkList[nlinkpos] = arr[ncid-1].pVer;/*相邻节点指针数组赋值*/
59 arr[nid-1].pVer->nCost[ncid-1] = ncost;/*此节点到相邻节点的cost*/
60 arr[nid-1].pVer->pmincost = NULL;
61 arr[nid-1].pVer->next = NULL;
62 nlinkpos++;
63 }
64 }
65 fclose(pfile);
66 return TRUE;
67 }
68 /*******************************************
69 *函数名:ViewGraphic
70 *参数:arr-图的数组
71 *返回值:无
72 *说明:打印图的结构信息
73 *******************************************/
74 void ViewGraphic(node arr[])
75 {
76 int i, j;
77 int nidtemp;//临时节点序号
78 printf("\nID\tConnceted to-ID:cost");
79 for(i=0; i<g_node_num; i++) {
80 printf("\n%d\t",arr[i].nID);
81 for(j=0; arr[i].pVer->pLinkList[j] != NULL; j++) {
82 nidtemp = arr[i].pVer->pLinkList[j]->id;
83 printf("%d:", nidtemp);
84 printf("%d ",arr[i].pVer->nCost[nidtemp-1]);
85 }
86 }
87 }
88 /*************************************************
89 *函数名:Dijkstra
90 *参数:arr-图的数组
91 *返回值:TRUE-成功;FALSE-失败
92 *说明:依次将每个节点作为起始节点,计算剩余节点与其之间的最短路径
93 *************************************************/
94 BOOL Dijkstra(node arr[])
95 {
96 UINT i, j, k;
97 vertex *pbegin, *ptemp, *ptemp1;
98 int *tcost;//用于储存其余节点到起始节点的最小代价
99 BOOL *pbDone;//用于判断节点是否计算完毕的数组
100 int nidtemp;//与当前节点相邻的其它节点中,cost最小的顶点序号
101 int nmixcost = INFINITE;
102
103 tcost = (int*)malloc(g_node_num * sizeof(int));
104 pbDone = (BOOL*)malloc(g_node_num * sizeof(BOOL));
105 if(NULL == tcost || NULL == pbDone) {
106 printf("out of memory\n");
107 return FALSE;
108 }
109 for(i=0; arr[i].pVer!=0; i++) {//依次将每个顶点作为起始节点
110 for(j=0; j<g_node_num; j++) {//初始化数组
111 tcost[j] = INFINITE;//其它节点到起始节点的代价
112 pbDone[j] = 0;
113 }
114 pbegin = arr[i].pVer;//起始顶点
115 pbegin->next = (vertex**)malloc(g_node_num * sizeof(vertex*));//储存每个顶点最优的前驱顶点的id的数组
116 pbegin->pmincost = (int*)malloc(g_node_num * sizeof(int));//储存每个顶点到起始顶点的最小代价数组
117 tcost[i] = 0;//初始化
118 pbDone[i] = 1;
119 pbegin->pmincost[i] = 0;
120 ptemp = pbegin;//设定起始顶点为当前顶点
121
122 while(1) {
123 for(j=0; ptemp->pLinkList[j]!=0; j++) {//遍历当前顶点的相邻节点,更新最小代价(松弛边)
124 ptemp1 = ptemp->pLinkList[j];
125 if(tcost[ptemp1->id-1] > tcost[ptemp->id-1] + ptemp->nCost[ptemp1->id-1] \
126 && pbDone[ptemp1->id-1] == 0) {
127 tcost[ptemp1->id-1] = tcost[ptemp->id-1] + ptemp->nCost[ptemp1->id-1];
128 pbegin->next[ptemp1->id-1] = ptemp;//设定顶点更新后的前驱顶点
129 }
130 }
131 nmixcost = INFINITE;
132 for(j=0; j<g_node_num; j++) {//找出更新后,所有顶点中,代价最小的顶点,重新作为当前顶点。这一步可以优化。
133 if(pbDone[arr[j].nID-1] != 1 && tcost[arr[j].nID-1] < nmixcost && tcost[arr[j].nID-1] != 0) {
134 nmixcost = tcost[arr[j].nID-1];
135 nidtemp = arr[j].nID;
136 }
137 }
138 if(nmixcost == INFINITE) {//除起始顶点外的所有节点都已经被处理完毕,退出
139 break;
140 }
141 pbegin->pmincost[nidtemp-1] = nmixcost;
142 ptemp = arr[nidtemp-1].pVer;//重新设定当前顶点
143 pbDone[nidtemp-1] = 1;//表示当前顶点已经被处理过了,其路径已经最短,代价最小
144 }
145 }
146 free(pbDone);
147 free(tcost);
148 return TRUE;
149 }
150 /**********************************************************
151 *函数名:MinRoute
152 *参数:arr-图的数组;nSrID-起始节点序号;nDsID-目的节点序号
153 *返回值:无
154 *说明:给定图的数组,利用Dijkstra函数处理之后,根据设定的起始和终止节点序号,打印
155 *最短路径和最小代价。
156 ***********************************************************/
157 void MinRoute(node arr[], UINT nSrID, UINT nDsID)
158 {
159 if(nSrID<0 || nSrID>g_node_num || nDsID<0 || nDsID>g_node_num) {
160 printf("Invalid node number!\n");
161 }
162 int nid;
163 vertex *ptemp = arr[nSrID-1].pVer;
164 printf("the total cost is: %d\n", ptemp->pmincost[nDsID-1]);
165 printf("the path is:");
166 nid = nDsID;
167 printf("%d->",arr[nid-1].nID);
168 while(ptemp->next[nid-1]->id != arr[nSrID-1].nID) {
169 nid = ptemp->next[nid-1]->id;//回溯路径
170 printf("%d->",nid);
171 }
172 printf("%d\n",arr[nSrID-1]);
173 }
174 /*****************************************
175 *函数名:UnitGraphic
176 *参数:arr-图的数组
177 *返回值:无
178 *说明:释放内存
179 *****************************************/
180 void UnitGraphic(node arr[])
181 {
182 UINT i;
183 for(i=0; i<g_node_num; i++) {
184 if(arr[i].pVer != NULL) {
185 SAFEFREE(arr[i].pVer->next);
186 SAFEFREE(arr[i].pVer->pmincost);
187 }
188 }
189 }