重复造轮子系列--dijkstra算法

Posted 丹西

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重复造轮子系列--dijkstra算法相关的知识,希望对你有一定的参考价值。

spf.h

 1 #ifndef SPF_H_
 2 #define SPF_H_
 3 
 4 
 5 typedef struct {
 6     int length;
 7     char src;
 8     char dst;
 9     char prev_hop;
10 } dijkstra; 
11 
12 #define MAX 1024
13 #define NODE_NUM 5
14 #define TRUE 1
15 #define FALSE 0
16 
17 #endif

spf.c

  1 #include <stdio.h>
  2 #include <stdarg.h>
  3 #include <string.h>
  4 #include <limits.h>
  5 #include <time.h>
  6 #include <sys/timeb.h>
  7 #include "spf.h"
  8 
  9 dijkstra DIJK[NODE_NUM][NODE_NUM] = {0};
 10 char NODES[NODE_NUM] = {A, B, C, D, E};
 11 int P_NDS[NODE_NUM] = {0};
 12 int U_NDS[NODE_NUM] = {0};
 13 
 14 int distance(char src, char dst);
 15 void debug(char* fmt,...);
 16 void spf_dijkstra_init();
 17 void spf_show_dijkstra_matrix(int top);
 18 dijkstra* spf_shortest_path_cost(char src, char dst);
 19 void spf_main(int src_top);
 20 int in_pnd_sets(char src);
 21 void spf_pu_sets_init();
 22 int spf_find_candidate_node(int src_top, int top);
 23 int spf_calc_next_hop(int src_top, int top, int min_idx);
 24 void time_show();
 25 
 26 int main(int argc, char **argv) {
 27     int i;
 28     //time_show();
 29     spf_dijkstra_init();
 30     for (i=0; i<NODE_NUM; i++) {
 31         spf_pu_sets_init();
 32         spf_main(i);
 33         //spf_show_dijkstra_matrix(i);
 34     }
 35     //time_show();
 36     return 0;
 37 }
 38 
 39 void spf_pu_sets_init() {
 40     memset(P_NDS, 0, sizeof(P_NDS));
 41     memset(U_NDS, 0, sizeof(U_NDS));
 42 }
 43 
 44 void spf_main(int src_top) {
 45     int top = src_top;
 46     int min_node_id = -1;
 47     int loop = 0;
 48     
 49     if (top >= NODE_NUM || top < 0) {
 50         debug("input error src_top = %d, input again plz \n");
 51         return;
 52     }
 53  
 54     P_NDS[top] = TRUE;
 55     while(TRUE) {
 56         if (loop == NODE_NUM) break;
 57         loop++;
 58 
 59         min_node_id = spf_find_candidate_node(src_top, top);
 60         if (min_node_id == -1) continue;
 61         top = spf_calc_next_hop(src_top, top, min_node_id);
 62         if (top<0 || top>NODE_NUM) continue;
 63         P_NDS[top] = TRUE;      
 64     }
 65     return;
 66 }
 67 
 68 int spf_find_candidate_node(int src_top, int top) {
 69     int min_idx = -1;
 70     int min_cost = MAX;
 71 
 72     for (int i=0; i<NODE_NUM; i++) {
 73         if (TRUE == P_NDS[i]) continue;  // 已经计算过路由的就不在计算   
 74                                      
 75         int d1 = distance(NODES[top], NODES[i]);
 76         if (MAX == d1 || 0 == d1) continue;
 77 
 78         U_NDS[i] = TRUE;
 79         dijkstra* dij_dst = spf_shortest_path_cost(NODES[src_top], NODES[i]);
 80         dijkstra* dij_hop = spf_shortest_path_cost(NODES[src_top], NODES[top]);
 81 
 82         if (NULL == dij_dst || NULL == dij_hop) continue;
 83 
 84         // 如果源顶点与当前节点的距离 > 源顶点与当前顶点的距离 + 当前顶点与当前节点的距离,
 85         // 则设置当前顶点为当前节点的上一跳节点
 86         // ‘S‘ 表示没有设置过上一跳节点
 87         if (dij_dst->length > d1+dij_hop->length || dij_dst->prev_hop == S) {
 88             dij_dst->prev_hop = NODES[top];
 89         }
 90 
 91         if (d1 < min_cost) {
 92             min_cost = d1;
 93             min_idx = i;            
 94         }
 95     }
 96 
 97     return min_idx;
 98 }
 99 
100 int spf_calc_next_hop(int src_top, int top, int min_idx) {
101     for (int i=0; i<NODE_NUM; i++) {
102         if (FALSE == U_NDS[i]) continue;
103         int d1 = distance(NODES[src_top], NODES[i]); 
104         int d2 = distance(NODES[top], NODES[i]); 
105 
106         if (0 == d2) continue;           
107         dijkstra* dij_top = spf_shortest_path_cost(NODES[src_top], NODES[top]);   
108         int d3 = d2 + dij_top->length;    
109         dijkstra* dij_dst = spf_shortest_path_cost(NODES[src_top], NODES[i]);
110         if (!dij_dst) continue;
111 
112         // 如果源顶点到当前节点的已经过计算的最短路径距离小于直接计算源顶点与当前节点距离
113         //,则使用最短路径距离
114         if (dij_dst->length < d1) d1 = dij_dst->length;                 
115 
116         // 如果源顶点与当前顶点的距离+当前顶点到当前节点的距离
117         // 小于直接计算源顶点与当前节点距离,
118         // 则把当前顶点设置为当前的节点上一跳
119         if (0 < d3 && d3 < MAX && d3 <= d1) {
120             dij_dst->prev_hop = NODES[top];
121             dij_dst->length = d3;
122             U_NDS[i] = FALSE;          
123         } 
124         // 如果当前节点的最短路径距离小于当前顶点计算的距离,
125         // 则调整当前节点上一跳,重新开始最短路由运算
126         else if (d1 > 0 && d1 < d3 && d3 < MAX) { 
127             int d = distance(dij_dst->src, dij_dst->dst);
128             // 如果源顶点与目标节点是直连,并且距离小于最短路径距离,
129             // 则设置上一条节点为源顶点
130             if (MAX!=d && d<dij_dst->length) 
131                 dij_dst->prev_hop = dij_dst->src;                
132 
133             P_NDS[top] = FALSE;
134             U_NDS[top] = TRUE;
135             min_idx = i;            
136         }           
137     }
138     return min_idx;
139 }
140 
141 int in_pnd_sets(char src) {
142     int i;
143     for (i=0; i<NODE_NUM; i++)
144         if (NODES[i] == src && P_NDS[i] == TRUE)
145             return TRUE;
146     return FALSE;
147 }
148 
149 void spf_dijkstra_init() {
150     int i,j;
151     for (i=0; i<NODE_NUM; i++) {
152         for (j=0; j<NODE_NUM; j++) {
153             DIJK[i][j].length = distance(NODES[i], NODES[j]);
154             DIJK[i][j].src = NODES[i];
155             DIJK[i][j].dst = NODES[j];    
156             DIJK[i][j].prev_hop = DIJK[i][j].length == 0 ? NODES[i] : S;   
157         }
158     }
159     return;
160 }
161 
162 void spf_show_dijkstra_matrix(int top) {
163     int i,j;
164     for (i=0; i<NODE_NUM; i++) {
165         for (j=0; j<NODE_NUM; j++) {
166             if (top == i && DIJK[i][j].src != DIJK[i][j].dst)
167                 printf("len=%d src=%c dst=%c prev=%c\n", 
168                 DIJK[i][j].length, DIJK[i][j].src,
169                 DIJK[i][j].dst, DIJK[i][j].prev_hop);
170         }        
171     }
172     printf("\n");
173     return;
174 }
175 
176 dijkstra* spf_shortest_path_cost(char src, char dst) {
177     dijkstra* dij = &DIJK[0][0];
178     for (int k=0; k<NODE_NUM*NODE_NUM; k++,dij++) {
179         if (dij->src == src && dij->dst == dst) 
180             return dij;
181     }
182 
183     return NULL;
184 }
185 
186 int distance(char src, char dst) {
187     if (src == dst) return 0;
188     if (A == src && B == dst) return 1;
189     if (B == src && A == dst) return 1;
190     if (A == src && C == dst) return 5;
191     if (C == src && A == dst) return 5;    
192     if (B == src && D == dst) return 6;
193     if (D == src && B == dst) return 6;
194     if (B == src && E == dst) return 2;
195     if (E == src && B == dst) return 2;
196     if (C == src && E == dst) return 1;
197     if (E == src && C == dst) return 1;
198     if (D == src && E == dst) return 1;
199     if (E == src && D == dst) return 1;
200     return MAX;
201 }

 

以上是关于重复造轮子系列--dijkstra算法的主要内容,如果未能解决你的问题,请参考以下文章

重复造轮子系列--插入排序和归并排序

重复造轮子系列--计数,基数排序

重复造轮子系列:分布式rpc框架设计_00

不重复造轮子系列JVM学习资源

重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印

「从零开始造 RPC 轮子系列」01 我为什么要去造一个轮子?