|
Graphviz
2.31.20130525.0447
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 00015 /****************************************** 00016 00017 Dijkstra algorithm 00018 Computes single-source distances for 00019 weighted graphs 00020 00021 ******************************************/ 00022 00023 00024 #include "bfs.h" 00025 #include "dijkstra.h" 00026 #include <limits.h> 00027 #include <stdlib.h> 00028 /* #include <math.h> */ 00029 00030 #define MAX_DIST (double)INT_MAX 00031 00032 typedef DistType Word; 00033 00034 #define LOOP while(TRUE) 00035 00036 /* This heap class is suited to the Dijkstra alg. 00037 data[i]=vertexNum <==> index[vertexNum]=i 00038 */ 00039 00040 #define left(i) (2*(i)) 00041 #define right(i) (2*(i)+1) 00042 #define parent(i) ((i)/2) 00043 #define insideHeap(h,i) ((i)<h->heapSize) 00044 #define greaterPriority(h,i,j,dist) (dist[h->data[i]]<dist[h->data[j]]) 00045 #define assign(h,i,j,index) {h->data[i]=h->data[j]; index[h->data[i]]=i;} 00046 #define exchange(h,i,j,index) {int temp; \ 00047 temp=h->data[i]; \ 00048 h->data[i]=h->data[j]; \ 00049 h->data[j]=temp; \ 00050 index[h->data[i]]=i; \ 00051 index[h->data[j]]=j; \ 00052 } 00053 00054 typedef struct { 00055 int *data; 00056 int heapSize; 00057 } heap; 00058 00059 static void heapify(heap * h, int i, int index[], Word dist[]) 00060 { 00061 int l, r, largest; 00062 while (1) { 00063 l = left(i); 00064 r = right(i); 00065 if (insideHeap(h, l) && greaterPriority(h, l, i, dist)) 00066 largest = l; 00067 else 00068 largest = i; 00069 if (insideHeap(h, r) && greaterPriority(h, r, largest, dist)) 00070 largest = r; 00071 00072 if (largest == i) 00073 break; 00074 00075 exchange(h, largest, i, index); 00076 i = largest; 00077 } 00078 } 00079 00080 #ifdef OBSOLETE 00081 /* originally, the code called mkHeap to allocate space, then 00082 * initHeap to realloc the space. This is silly. 00083 * Now we just call initHeap. 00084 */ 00085 static void mkHeap(heap * h, int size) 00086 { 00087 h->data = N_GNEW(size, int); 00088 h->heapSize = 0; 00089 } 00090 #endif 00091 00092 static void freeHeap(heap * h) 00093 { 00094 if (h->data) free(h->data); 00095 } 00096 00097 static void 00098 initHeap(heap * h, int startVertex, int index[], Word dist[], int n) 00099 { 00100 int i, count; 00101 int j; /* We cannot use an unsigned value in this loop */ 00102 /* h->data=(int*) realloc(h->data, (n-1)*sizeof(int)); */ 00103 if (n == 1) h->data = NULL; 00104 else h->data = N_GNEW(n - 1, int); 00105 h->heapSize = n - 1; 00106 00107 for (count = 0, i = 0; i < n; i++) 00108 if (i != startVertex) { 00109 h->data[count] = i; 00110 index[i] = count; 00111 count++; 00112 } 00113 00114 for (j = (n - 1) / 2; j >= 0; j--) 00115 heapify(h, j, index, dist); 00116 } 00117 00118 static boolean extractMax(heap * h, int *max, int index[], Word dist[]) 00119 { 00120 if (h->heapSize == 0) 00121 return FALSE; 00122 00123 *max = h->data[0]; 00124 h->data[0] = h->data[h->heapSize - 1]; 00125 index[h->data[0]] = 0; 00126 h->heapSize--; 00127 heapify(h, 0, index, dist); 00128 00129 return TRUE; 00130 } 00131 00132 static void 00133 increaseKey(heap * h, int increasedVertex, Word newDist, int index[], 00134 Word dist[]) 00135 { 00136 int placeInHeap; 00137 int i; 00138 00139 if (dist[increasedVertex] <= newDist) 00140 return; 00141 00142 placeInHeap = index[increasedVertex]; 00143 00144 dist[increasedVertex] = newDist; 00145 00146 i = placeInHeap; 00147 while (i > 0 && dist[h->data[parent(i)]] > newDist) { /* can write here: greaterPriority(i,parent(i),dist) */ 00148 assign(h, i, parent(i), index); 00149 i = parent(i); 00150 } 00151 h->data[i] = increasedVertex; 00152 index[increasedVertex] = i; 00153 } 00154 00155 void dijkstra(int vertex, vtx_data * graph, int n, DistType * dist) 00156 { 00157 int i; 00158 heap H; 00159 int closestVertex, neighbor; 00160 DistType closestDist, prevClosestDist = INT_MAX; 00161 static int *index; 00162 00163 #ifdef OBSOLETE 00164 mkHeap(&H, n); 00165 #endif 00166 index = (int *) realloc(index, n * sizeof(int)); 00167 00168 /* initial distances with edge weights: */ 00169 for (i = 0; i < n; i++) 00170 dist[i] = (DistType) MAX_DIST; 00171 dist[vertex] = 0; 00172 for (i = 1; i < graph[vertex].nedges; i++) 00173 dist[graph[vertex].edges[i]] = (DistType) graph[vertex].ewgts[i]; 00174 00175 initHeap(&H, vertex, index, dist, n); 00176 00177 while (extractMax(&H, &closestVertex, index, dist)) { 00178 closestDist = dist[closestVertex]; 00179 if (closestDist == MAX_DIST) 00180 break; 00181 for (i = 1; i < graph[closestVertex].nedges; i++) { 00182 neighbor = graph[closestVertex].edges[i]; 00183 increaseKey(&H, neighbor, 00184 closestDist + 00185 (DistType) graph[closestVertex].ewgts[i], index, 00186 dist); 00187 } 00188 prevClosestDist = closestDist; 00189 } 00190 00191 /* For dealing with disconnected graphs: */ 00192 for (i = 0; i < n; i++) 00193 if (dist[i] == MAX_DIST) /* 'i' is not connected to 'vertex' */ 00194 dist[i] = prevClosestDist + 10; 00195 freeHeap(&H); 00196 } 00197 00198 /* Dijkstra bounded to nodes in *unweighted* radius */ 00199 int 00200 dijkstra_bounded(int vertex, vtx_data * graph, int n, DistType * dist, 00201 int bound, int *visited_nodes) 00202 /* make dijkstra, but consider only nodes whose *unweighted* distance from 'vertex' */ 00203 /* is at most 'bound' */ 00204 /* MON-EFFICIENT implementation, see below. */ 00205 { 00206 int num_visited_nodes; 00207 int i; 00208 static boolean *node_in_neighborhood = NULL; 00209 static int size = 0; 00210 static int *index; 00211 Queue Q; 00212 heap H; 00213 int closestVertex, neighbor; 00214 DistType closestDist; 00215 int num_found = 0; 00216 00217 /* first, perform BFS to find the nodes in the region */ 00218 mkQueue(&Q, n); 00219 /* remember that dist should be init. with -1's */ 00220 for (i = 0; i < n; i++) { 00221 dist[i] = -1; /* far, TOO COSTLY (O(n))! */ 00222 } 00223 num_visited_nodes = 00224 bfs_bounded(vertex, graph, n, dist, &Q, bound, visited_nodes); 00225 if (size < n) { 00226 node_in_neighborhood = 00227 (boolean *) realloc(node_in_neighborhood, n * sizeof(boolean)); 00228 for (i = size; i < n; i++) { 00229 node_in_neighborhood[i] = FALSE; 00230 } 00231 size = n; 00232 } 00233 for (i = 0; i < num_visited_nodes; i++) { 00234 node_in_neighborhood[visited_nodes[i]] = TRUE; 00235 } 00236 00237 00238 #ifdef OBSOLETE 00239 mkHeap(&H, n); 00240 #endif 00241 index = (int *) realloc(index, n * sizeof(int)); 00242 00243 /* initial distances with edge weights: */ 00244 for (i = 0; i < n; i++) /* far, TOO COSTLY (O(n))! */ 00245 dist[i] = (DistType) MAX_DIST; 00246 dist[vertex] = 0; 00247 for (i = 1; i < graph[vertex].nedges; i++) 00248 dist[graph[vertex].edges[i]] = (DistType) graph[vertex].ewgts[i]; 00249 00250 /* again, TOO COSTLY (O(n)) to put all nodes in heap! */ 00251 initHeap(&H, vertex, index, dist, n); 00252 00253 while (num_found < num_visited_nodes 00254 && extractMax(&H, &closestVertex, index, dist)) { 00255 if (node_in_neighborhood[closestVertex]) { 00256 num_found++; 00257 } 00258 closestDist = dist[closestVertex]; 00259 if (closestDist == MAX_DIST) 00260 break; 00261 for (i = 1; i < graph[closestVertex].nedges; i++) { 00262 neighbor = graph[closestVertex].edges[i]; 00263 increaseKey(&H, neighbor, 00264 closestDist + 00265 (DistType) graph[closestVertex].ewgts[i], index, 00266 dist); 00267 } 00268 } 00269 00270 /* restore initial false-status of 'node_in_neighborhood' */ 00271 for (i = 0; i < num_visited_nodes; i++) { 00272 node_in_neighborhood[visited_nodes[i]] = FALSE; 00273 } 00274 freeHeap(&H); 00275 freeQueue(&Q); 00276 return num_visited_nodes; 00277 } 00278 00279 static void heapify_f(heap * h, int i, int index[], float dist[]) 00280 { 00281 int l, r, largest; 00282 while (1) { 00283 l = left(i); 00284 r = right(i); 00285 if (insideHeap(h, l) && greaterPriority(h, l, i, dist)) 00286 largest = l; 00287 else 00288 largest = i; 00289 if (insideHeap(h, r) && greaterPriority(h, r, largest, dist)) 00290 largest = r; 00291 00292 if (largest == i) 00293 break; 00294 00295 exchange(h, largest, i, index); 00296 i = largest; 00297 } 00298 } 00299 00300 static void 00301 initHeap_f(heap * h, int startVertex, int index[], float dist[], int n) 00302 { 00303 int i, count; 00304 int j; /* We cannot use an unsigned value in this loop */ 00305 h->data = N_GNEW(n - 1, int); 00306 h->heapSize = n - 1; 00307 00308 for (count = 0, i = 0; i < n; i++) 00309 if (i != startVertex) { 00310 h->data[count] = i; 00311 index[i] = count; 00312 count++; 00313 } 00314 00315 for (j = (n - 1) / 2; j >= 0; j--) 00316 heapify_f(h, j, index, dist); 00317 } 00318 00319 static boolean extractMax_f(heap * h, int *max, int index[], float dist[]) 00320 { 00321 if (h->heapSize == 0) 00322 return FALSE; 00323 00324 *max = h->data[0]; 00325 h->data[0] = h->data[h->heapSize - 1]; 00326 index[h->data[0]] = 0; 00327 h->heapSize--; 00328 heapify_f(h, 0, index, dist); 00329 00330 return TRUE; 00331 } 00332 00333 static void 00334 increaseKey_f(heap * h, int increasedVertex, float newDist, int index[], 00335 float dist[]) 00336 { 00337 int placeInHeap; 00338 int i; 00339 00340 if (dist[increasedVertex] <= newDist) 00341 return; 00342 00343 placeInHeap = index[increasedVertex]; 00344 00345 dist[increasedVertex] = newDist; 00346 00347 i = placeInHeap; 00348 while (i > 0 && dist[h->data[parent(i)]] > newDist) { /* can write here: greaterPriority(i,parent(i),dist) */ 00349 assign(h, i, parent(i), index); 00350 i = parent(i); 00351 } 00352 h->data[i] = increasedVertex; 00353 index[increasedVertex] = i; 00354 } 00355 00356 /* dijkstra_f: 00357 * Weighted shortest paths from vertex. 00358 * Assume graph is connected. 00359 */ 00360 void dijkstra_f(int vertex, vtx_data * graph, int n, float *dist) 00361 { 00362 int i; 00363 heap H; 00364 int closestVertex = 0, neighbor; 00365 float closestDist; 00366 int *index; 00367 00368 #ifdef OBSOLETE 00369 mkHeap(&H, n); 00370 #endif 00371 index = N_GNEW(n, int); 00372 00373 /* initial distances with edge weights: */ 00374 for (i = 0; i < n; i++) 00375 dist[i] = MAXFLOAT; 00376 dist[vertex] = 0; 00377 for (i = 1; i < graph[vertex].nedges; i++) 00378 dist[graph[vertex].edges[i]] = graph[vertex].ewgts[i]; 00379 00380 initHeap_f(&H, vertex, index, dist, n); 00381 00382 while (extractMax_f(&H, &closestVertex, index, dist)) { 00383 closestDist = dist[closestVertex]; 00384 if (closestDist == MAXFLOAT) 00385 break; 00386 for (i = 1; i < graph[closestVertex].nedges; i++) { 00387 neighbor = graph[closestVertex].edges[i]; 00388 increaseKey_f(&H, neighbor, 00389 closestDist + graph[closestVertex].ewgts[i], 00390 index, dist); 00391 } 00392 } 00393 00394 freeHeap(&H); 00395 free(index); 00396 }
1.7.5