1. 1 /**
  2. 2 * C: Dijkstra算法获取最短路径(邻接矩阵)
  3. 3 *

    6 */
  4. 7
  5. 8 #include <stdio.h>
  6. 9 #include <stdlib.h>
  7. 10 #include <malloc.h>
  8. 11 #include <string.h>
  9. 12
  10. 13 #define MAX 100 // 矩阵最大容量
  11. 14 #define INF (~(0x1<<31)) // 最大值(即0X7FFFFFFF)
  12. 15 #define isLetter(a) ((((a)>='a')&&((a)<='z')) || (((a)>='A')&&((a)<='Z')))
  13. 16 #define LENGTH(a) (sizeof(a)/sizeof(a[0]))
  14. 17
  15. 18 // 邻接矩阵
  16. 19 typedef struct _graph
  17. 20 {
  18. 21 char vexs[MAX]; // 顶点集合
  19. 22 int vexnum; // 顶点数
  20. 23 int edgnum; // 边数
  21. 24 int matrix[MAX][MAX]; // 邻接矩阵
  22. 25 }Graph, *PGraph;
  23. 26
  24. 27 // 边的结构体
  25. 28 typedef struct _EdgeData
  26. 29 {
  27. 30 char start; // 边的起点
  28. 31 char end; // 边的终点
  29. 32 int weight; // 边的权重
  30. 33 }EData;
  31. 34
  32. 35 /*
  33. 36 * 返回ch在matrix矩阵中的位置
  34. 37 */
  35. 38 static int get_position(Graph G, char ch)
  36. 39 {
  37. 40 int i;
  38. 41 for(i=0; i<G.vexnum; i++)
  39. 42 if(G.vexs[i]==ch)
  40. 43 return i;
  41. 44 return -1;
  42. 45 }
  43. 46
  44. 47 /*
  45. 48 * 读取一个输入字符
  46. 49 */
  47. 50 static char read_char()
  48. 51 {
  49. 52 char ch;
  50. 53
  51. 54 do {
  52. 55 ch = getchar();
  53. 56 } while(!isLetter(ch));
  54. 57
  55. 58 return ch;
  56. 59 }
  57. 60
  58. 61 /*
  59. 62 * 创建图(自己输入)
  60. 63 */
  61. 64 Graph* create_graph()
  62. 65 {
  63. 66 char c1, c2;
  64. 67 int v, e;
  65. 68 int i, j, weight, p1, p2;
  66. 69 Graph* pG;
  67. 70
  68. 71 // 输入"顶点数"和"边数"
  69. 72 printf("input vertex number: ");
  70. 73 scanf("%d", &v);
  71. 74 printf("input edge number: ");
  72. 75 scanf("%d", &e);
  73. 76 if ( v < 1 || e < 1 || (e > (v * (v-1))))
  74. 77 {
  75. 78 printf("input error: invalid parameters!\n");
  76. 79 return NULL;
  77. 80 }
  78. 81
  79. 82 if ((pG=(Graph*)malloc(sizeof(Graph))) == NULL )
  80. 83 return NULL;
  81. 84 memset(pG, 0, sizeof(Graph));
  82. 85
  83. 86 // 初始化"顶点数"和"边数"
  84. 87 pG->vexnum = v;
  85. 88 pG->edgnum = e;
  86. 89 // 初始化"顶点"
  87. 90 for (i = 0; i < pG->vexnum; i++)
  88. 91 {
  89. 92 printf("vertex(%d): ", i);
  90. 93 pG->vexs[i] = read_char();
  91. 94 }
  92. 95
  93. 96 // 1. 初始化"边"的权值
  94. 97 for (i = 0; i < pG->vexnum; i++)
  95. 98 {
  96. 99 for (j = 0; j < pG->vexnum; j++)
  97. 100 {
  98. 101 if (i==j)
  99. 102 pG->matrix[i][j] = 0;
  100. 103 else
  101. 104 pG->matrix[i][j] = INF;
  102. 105 }
  103. 106 }
  104. 107 // 2. 初始化"边"的权值: 根据用户的输入进行初始化
  105. 108 for (i = 0; i < pG->edgnum; i++)
  106. 109 {
  107. 110 // 读取边的起始顶点,结束顶点,权值
  108. 111 printf("edge(%d):", i);
  109. 112 c1 = read_char();
  110. 113 c2 = read_char();
  111. 114 scanf("%d", &weight);
  112. 115
  113. 116 p1 = get_position(*pG, c1);
  114. 117 p2 = get_position(*pG, c2);
  115. 118 if (p1==-1 || p2==-1)
  116. 119 {
  117. 120 printf("input error: invalid edge!\n");
  118. 121 free(pG);
  119. 122 return NULL;
  120. 123 }
  121. 124
  122. 125 pG->matrix[p1][p2] = weight;
  123. 126 pG->matrix[p2][p1] = weight;
  124. 127 }
  125. 128
  126. 129 return pG;
  127. 130 }
  128. 131
  129. 132 /*
  130. 133 * 创建图(用已提供的矩阵)
  131. 134 */
  132. 135 Graph* create_example_graph()
  133. 136 {
  134. 137 char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
  135. 138 int matrix[][9] = {
  136. 139 /*A*//*B*//*C*//*D*//*E*//*F*//*G*/
  137. 140 /*A*/ { 0, 12, INF, INF, INF, 16, 14},
  138. 141 /*B*/ { 12, 0, 10, INF, INF, 7, INF},
  139. 142 /*C*/ { INF, 10, 0, 3, 5, 6, INF},
  140. 143 /*D*/ { INF, INF, 3, 0, 4, INF, INF},
  141. 144 /*E*/ { INF, INF, 5, 4, 0, 2, 8},
  142. 145 /*F*/ { 16, 7, 6, INF, 2, 0, 9},
  143. 146 /*G*/ { 14, INF, INF, INF, 8, 9, 0}};
  144. 147 int vlen = LENGTH(vexs);
  145. 148 int i, j;
  146. 149 Graph* pG;
  147. 150
  148. 151 // 输入"顶点数"和"边数"
  149. 152 if ((pG=(Graph*)malloc(sizeof(Graph))) == NULL )
  150. 153 return NULL;
  151. 154 memset(pG, 0, sizeof(Graph));
  152. 155
  153. 156 // 初始化"顶点数"
  154. 157 pG->vexnum = vlen;
  155. 158 // 初始化"顶点"
  156. 159 for (i = 0; i < pG->vexnum; i++)
  157. 160 pG->vexs[i] = vexs[i];
  158. 161
  159. 162 // 初始化"边"
  160. 163 for (i = 0; i < pG->vexnum; i++)
  161. 164 for (j = 0; j < pG->vexnum; j++)
  162. 165 pG->matrix[i][j] = matrix[i][j];
  163. 166
  164. 167 // 统计边的数目
  165. 168 for (i = 0; i < pG->vexnum; i++)
  166. 169 for (j = 0; j < pG->vexnum; j++)
  167. 170 if (i!=j && pG->matrix[i][j]!=INF)
  168. 171 pG->edgnum++;
  169. 172 pG->edgnum /= 2;
  170. 173
  171. 174 return pG;
  172. 175 }
  173. 176
  174. 177 /*
  175. 178 * 返回顶点v的第一个邻接顶点的索引,失败则返回-1
  176. 179 */
  177. 180 static int first_vertex(Graph G, int v)
  178. 181 {
  179. 182 int i;
  180. 183
  181. 184 if (v<0 || v>(G.vexnum-1))
  182. 185 return -1;
  183. 186
  184. 187 for (i = 0; i < G.vexnum; i++)
  185. 188 if (G.matrix[v][i]!=0 && G.matrix[v][i]!=INF)
  186. 189 return i;
  187. 190
  188. 191 return -1;
  189. 192 }
  190. 193
  191. 194 /*
  192. 195 * 返回顶点v相对于w的下一个邻接顶点的索引,失败则返回-1
  193. 196 */
  194. 197 static int next_vertix(Graph G, int v, int w)
  195. 198 {
  196. 199 int i;
  197. 200
  198. 201 if (v<0 || v>(G.vexnum-1) || w<0 || w>(G.vexnum-1))
  199. 202 return -1;
  200. 203
  201. 204 for (i = w + 1; i < G.vexnum; i++)
  202. 205 if (G.matrix[v][i]!=0 && G.matrix[v][i]!=INF)
  203. 206 return i;
  204. 207
  205. 208 return -1;
  206. 209 }
  207. 210
  208. 211 /*
  209. 212 * 深度优先搜索遍历图的递归实现
  210. 213 */
  211. 214 static void DFS(Graph G, int i, int *visited)
  212. 215 {
  213. 216 int w;
  214. 217
  215. 218 visited[i] = 1;
  216. 219 printf("%c ", G.vexs[i]);
  217. 220 // 遍历该顶点的所有邻接顶点。若是没有访问过,那么继续往下走
  218. 221 for (w = first_vertex(G, i); w >= 0; w = next_vertix(G, i, w))
  219. 222 {
  220. 223 if (!visited[w])
  221. 224 DFS(G, w, visited);
  222. 225 }
  223. 226
  224. 227 }
  225. 228
  226. 229 /*
  227. 230 * 深度优先搜索遍历图
  228. 231 */
  229. 232 void DFSTraverse(Graph G)
  230. 233 {
  231. 234 int i;
  232. 235 int visited[MAX]; // 顶点访问标记
  233. 236
  234. 237 // 初始化所有顶点都没有被访问
  235. 238 for (i = 0; i < G.vexnum; i++)
  236. 239 visited[i] = 0;
  237. 240
  238. 241 printf("DFS: ");
  239. 242 for (i = 0; i < G.vexnum; i++)
  240. 243 {
  241. 244 //printf("\n== LOOP(%d)\n", i);
  242. 245 if (!visited[i])
  243. 246 DFS(G, i, visited);
  244. 247 }
  245. 248 printf("\n");
  246. 249 }
  247. 250
  248. 251 /*
  249. 252 * 广度优先搜索(类似于树的层次遍历)
  250. 253 */
  251. 254 void BFS(Graph G)
  252. 255 {
  253. 256 int head = 0;
  254. 257 int rear = 0;
  255. 258 int queue[MAX]; // 辅组队列
  256. 259 int visited[MAX]; // 顶点访问标记
  257. 260 int i, j, k;
  258. 261
  259. 262 for (i = 0; i < G.vexnum; i++)
  260. 263 visited[i] = 0;
  261. 264
  262. 265 printf("BFS: ");
  263. 266 for (i = 0; i < G.vexnum; i++)
  264. 267 {
  265. 268 if (!visited[i])
  266. 269 {
  267. 270 visited[i] = 1;
  268. 271 printf("%c ", G.vexs[i]);
  269. 272 queue[rear++] = i; // 入队列
  270. 273 }
  271. 274 while (head != rear)
  272. 275 {
  273. 276 j = queue[head++]; // 出队列
  274. 277 for (k = first_vertex(G, j); k >= 0; k = next_vertix(G, j, k)) //k是为访问的邻接顶点
  275. 278 {
  276. 279 if (!visited[k])
  277. 280 {
  278. 281 visited[k] = 1;
  279. 282 printf("%c ", G.vexs[k]);
  280. 283 queue[rear++] = k;
  281. 284 }
  282. 285 }
  283. 286 }
  284. 287 }
  285. 288 printf("\n");
  286. 289 }
  287. 290
  288. 291 /*
  289. 292 * 打印矩阵队列图
  290. 293 */
  291. 294 void print_graph(Graph G)
  292. 295 {
  293. 296 int i,j;
  294. 297
  295. 298 printf("Martix Graph:\n");
  296. 299 for (i = 0; i < G.vexnum; i++)
  297. 300 {
  298. 301 for (j = 0; j < G.vexnum; j++)
  299. 302 printf("%10d ", G.matrix[i][j]);
  300. 303 printf("\n");
  301. 304 }
  302. 305 }
  303. 306
  304. 307 /*
  305. 308 * prim最小生成树
  306. 309 *
  307. 310 * 参数说明:
  308. 311 * G -- 邻接矩阵图
  309. 312 * start -- 从图中的第start个元素开始,生成最小树
  310. 313 */
  311. 314 void prim(Graph G, int start)
  312. 315 {
  313. 316 int min,i,j,k,m,n,sum;
  314. 317 int index=0; // prim最小树的索引,即prims数组的索引
  315. 318 char prims[MAX]; // prim最小树的结果数组
  316. 319 int weights[MAX]; // 顶点间边的权值
  317. 320
  318. 321 // prim最小生成树中第一个数是"图中第start个顶点",因为是从start开始的。
  319. 322 prims[index++] = G.vexs[start];
  320. 323
  321. 324 // 初始化"顶点的权值数组",
  322. 325 // 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。
  323. 326 for (i = 0; i < G.vexnum; i++ )
  324. 327 weights[i] = G.matrix[start][i];
  325. 328 // 将第start个顶点的权值初始化为0。
  326. 329 // 可以理解为"第start个顶点到它自身的距离为0"。
  327. 330 weights[start] = 0;
  328. 331
  329. 332 for (i = 0; i < G.vexnum; i++)
  330. 333 {
  331. 334 // 由于从start开始的,因此不需要再对第start个顶点进行处理。
  332. 335 if(start == i)
  333. 336 continue;
  334. 337
  335. 338 j = 0;
  336. 339 k = 0;
  337. 340 min = INF;
  338. 341 // 在未被加入到最小生成树的顶点中,找出权值最小的顶点。
  339. 342 while (j < G.vexnum)
  340. 343 {
  341. 344 // 若weights[j]=0,意味着"第j个节点已经被排序过"(或者说已经加入了最小生成树中)。
  342. 345 if (weights[j] != 0 && weights[j] < min)
  343. 346 {
  344. 347 min = weights[j];
  345. 348 k = j;
  346. 349 }
  347. 350 j++;
  348. 351 }
  349. 352
  350. 353 // 经过上面的处理后,在未被加入到最小生成树的顶点中,权值最小的顶点是第k个顶点。
  351. 354 // 将第k个顶点加入到最小生成树的结果数组中
  352. 355 prims[index++] = G.vexs[k];
  353. 356 // 将"第k个顶点的权值"标记为0,意味着第k个顶点已经排序过了(或者说已经加入了最小树结果中)。
  354. 357 weights[k] = 0;
  355. 358 // 当第k个顶点被加入到最小生成树的结果数组中之后,更新其它顶点的权值。
  356. 359 for (j = 0 ; j < G.vexnum; j++)
  357. 360 {
  358. 361 // 当第j个节点没有被处理,并且需要更新时才被更新。
  359. 362 if (weights[j] != 0 && G.matrix[k][j] < weights[j])
  360. 363 weights[j] = G.matrix[k][j];
  361. 364 }
  362. 365 }
  363. 366
  364. 367 // 计算最小生成树的权值
  365. 368 sum = 0;
  366. 369 for (i = 1; i < index; i++)
  367. 370 {
  368. 371 min = INF;
  369. 372 // 获取prims[i]在G中的位置
  370. 373 n = get_position(G, prims[i]);
  371. 374 // 在vexs[0...i]中,找出到j的权值最小的顶点。
  372. 375 for (j = 0; j < i; j++)
  373. 376 {
  374. 377 m = get_position(G, prims[j]);
  375. 378 if (G.matrix[m][n]<min)
  376. 379 min = G.matrix[m][n];
  377. 380 }
  378. 381 sum += min;
  379. 382 }
  380. 383 // 打印最小生成树
  381. 384 printf("PRIM(%c)=%d: ", G.vexs[start], sum);
  382. 385 for (i = 0; i < index; i++)
  383. 386 printf("%c ", prims[i]);
  384. 387 printf("\n");
  385. 388 }
  386. 389
  387. 390 /*
  388. 391 * 获取图中的边
  389. 392 */
  390. 393 EData* get_edges(Graph G)
  391. 394 {
  392. 395 int i,j;
  393. 396 int index=0;
  394. 397 EData *edges;
  395. 398
  396. 399 edges = (EData*)malloc(G.edgnum*sizeof(EData));
  397. 400 for (i=0;i < G.vexnum;i++)
  398. 401 {
  399. 402 for (j=i+1;j < G.vexnum;j++)
  400. 403 {
  401. 404 if (G.matrix[i][j]!=INF)
  402. 405 {
  403. 406 edges[index].start = G.vexs[i];
  404. 407 edges[index].end = G.vexs[j];
  405. 408 edges[index].weight = G.matrix[i][j];
  406. 409 index++;
  407. 410 }
  408. 411 }
  409. 412 }
  410. 413
  411. 414 return edges;
  412. 415 }
  413. 416
  414. 417 /*
  415. 418 * 对边按照权值大小进行排序(由小到大)
  416. 419 */
  417. 420 void sorted_edges(EData* edges, int elen)
  418. 421 {
  419. 422 int i,j;
  420. 423
  421. 424 for (i=0; i<elen; i++)
  422. 425 {
  423. 426 for (j=i+1; j<elen; j++)
  424. 427 {
  425. 428 if (edges[i].weight > edges[j].weight)
  426. 429 {
  427. 430 // 交换"第i条边"和"第j条边"
  428. 431 EData tmp = edges[i];
  429. 432 edges[i] = edges[j];
  430. 433 edges[j] = tmp;
  431. 434 }
  432. 435 }
  433. 436 }
  434. 437 }
  435. 438
  436. 439 /*
  437. 440 * 获取i的终点
  438. 441 */
  439. 442 int get_end(int vends[], int i)
  440. 443 {
  441. 444 while (vends[i] != 0)
  442. 445 i = vends[i];
  443. 446 return i;
  444. 447 }
  445. 448
  446. 449 /*
  447. 450 * 克鲁斯卡尔(Kruskal)最小生成树
  448. 451 */
  449. 452 void kruskal(Graph G)
  450. 453 {
  451. 454 int i,m,n,p1,p2;
  452. 455 int length;
  453. 456 int index = 0; // rets数组的索引
  454. 457 int vends[MAX]={0}; // 用于保存"已有最小生成树"中每个顶点在该最小树中的终点。
  455. 458 EData rets[MAX]; // 结果数组,保存kruskal最小生成树的边
  456. 459 EData *edges; // 图对应的所有边
  457. 460
  458. 461 // 获取"图中所有的边"
  459. 462 edges = get_edges(G);
  460. 463 // 将边按照"权"的大小进行排序(从小到大)
  461. 464 sorted_edges(edges, G.edgnum);
  462. 465
  463. 466 for (i=0; i<G.edgnum; i++)
  464. 467 {
  465. 468 p1 = get_position(G, edges[i].start); // 获取第i条边的"起点"的序号
  466. 469 p2 = get_position(G, edges[i].end); // 获取第i条边的"终点"的序号
  467. 470
  468. 471 m = get_end(vends, p1); // 获取p1在"已有的最小生成树"中的终点
  469. 472 n = get_end(vends, p2); // 获取p2在"已有的最小生成树"中的终点
  470. 473 // 如果m!=n,意味着"边i"与"已经添加到最小生成树中的顶点"没有形成环路
  471. 474 if (m != n)
  472. 475 {
  473. 476 vends[m] = n; // 设置m在"已有的最小生成树"中的终点为n
  474. 477 rets[index++] = edges[i]; // 保存结果
  475. 478 }
  476. 479 }
  477. 480 free(edges);
  478. 481
  479. 482 // 统计并打印"kruskal最小生成树"的信息
  480. 483 length = 0;
  481. 484 for (i = 0; i < index; i++)
  482. 485 length += rets[i].weight;
  483. 486 printf("Kruskal=%d: ", length);
  484. 487 for (i = 0; i < index; i++)
  485. 488 printf("(%c,%c) ", rets[i].start, rets[i].end);
  486. 489 printf("\n");
  487. 490 }
  488. 491
  489. 492 /*
  490. 493 * Dijkstra最短路径。
  491. 494 * 即,统计图(G)中"顶点vs"到其它各个顶点的最短路径。
  492. 495 *
  493. 496 * 参数说明:
  494. 497 * G -- 图
  495. 498 * vs -- 起始顶点(start vertex)。即计算"顶点vs"到其它顶点的最短路径。
  496. 499 * prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
  497. 500 * dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。
  498. 501 */
  499. 502 void dijkstra(Graph G, int vs, int prev[], int dist[])
  500. 503 {
  501. 504 int i,j,k;
  502. 505 int min;
  503. 506 int tmp;
  504. 507 int flag[MAX]; // flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。
  505. 508
  506. 509 // 初始化
  507. 510 for (i = 0; i < G.vexnum; i++)
  508. 511 {
  509. 512 flag[i] = 0; // 顶点i的最短路径还没获取到。
  510. 513 prev[i] = 0; // 顶点i的前驱顶点为0。
  511. 514 dist[i] = G.matrix[vs][i];// 顶点i的最短路径为"顶点vs"到"顶点i"的权。
  512. 515 }
  513. 516
  514. 517 // 对"顶点vs"自身进行初始化
  515. 518 flag[vs] = 1;
  516. 519 dist[vs] = 0;
  517. 520
  518. 521 // 遍历G.vexnum-1次;每次找出一个顶点的最短路径。
  519. 522 for (i = 1; i < G.vexnum; i++)
  520. 523 {
  521. 524 // 寻找当前最小的路径;
  522. 525 // 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。
  523. 526 min = INF;
  524. 527 for (j = 0; j < G.vexnum; j++)
  525. 528 {
  526. 529 if (flag[j]==0 && dist[j]<min)
  527. 530 {
  528. 531 min = dist[j];
  529. 532 k = j;
  530. 533 }
  531. 534 }
  532. 535 // 标记"顶点k"为已经获取到最短路径
  533. 536 flag[k] = 1;
  534. 537
  535. 538 // 修正当前最短路径和前驱顶点
  536. 539 // 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。
  537. 540 for (j = 0; j < G.vexnum; j++)
  538. 541 {
  539. 542 tmp = (G.matrix[k][j]==INF ? INF : (min + G.matrix[k][j])); // 防止溢出
  540. 543 if (flag[j] == 0 && (tmp < dist[j]) )
  541. 544 {
  542. 545 dist[j] = tmp;
  543. 546 prev[j] = k;
  544. 547 }
  545. 548 }
  546. 549 }
  547. 550
  548. 551 // 打印dijkstra最短路径的结果
  549. 552 printf("dijkstra(%c): \n", G.vexs[vs]);
  550. 553 for (i = 0; i < G.vexnum; i++)
  551. 554 printf(" shortest(%c, %c)=%d\n", G.vexs[vs], G.vexs[i], dist[i]);
  552. 555 }
  553. 556
  554. 557 void main()
  555. 558 {
  556. 559 int prev[MAX] = {0};
  557. 560 int dist[MAX] = {0};
  558. 561 Graph* pG;
  559. 562
  560. 563 // 自定义"图"(输入矩阵队列)
  561. 564 //pG = create_graph();
  562. 565 // 采用已有的"图"
  563. 566 pG = create_example_graph();
  564. 567
  565. 568 //print_graph(*pG); // 打印图
  566. 569 //DFSTraverse(*pG); // 深度优先遍历
  567. 570 //BFS(*pG); // 广度优先遍历
  568. 571 //prim(*pG, 0); // prim算法生成最小生成树
  569. 572 //kruskal(*pG); // kruskal算法生成最小生成树
  570. 573
  571. 574 // dijkstra算法获取"第4个顶点"到其它各个顶点的最短距离
  572. 575 dijkstra(*pG, 3, prev, dist);
  573. 576 }
  1. 1
  2. 2 /**
  3. 3 * C: Dijkstra算法获取最短路径(邻接表)
  4. 4 *


  5. 7 */
  6. 8
  7. 9 #include <stdio.h>
  8. 10 #include <stdlib.h>
  9. 11 #include <malloc.h>
  10. 12 #include <string.h>
  11. 13
  12. 14 #define MAX 100
  13. 15 #define INF (~(0x1<<31)) // 最大值(即0X7FFFFFFF)
  14. 16 #define isLetter(a) ((((a)>='a')&&((a)<='z')) || (((a)>='A')&&((a)<='Z')))
  15. 17 #define LENGTH(a) (sizeof(a)/sizeof(a[0]))
  16. 18
  17. 19 // 邻接表中表对应的链表的顶点
  18. 20 typedef struct _ENode
  19. 21 {
  20. 22 int ivex; // 该边的顶点的位置
  21. 23 int weight; // 该边的权
  22. 24 struct _ENode *next_edge; // 指向下一条弧的指针
  23. 25 }ENode, *PENode;
  24. 26
  25. 27 // 邻接表中表的顶点
  26. 28 typedef struct _VNode
  27. 29 {
  28. 30 char data; // 顶点信息
  29. 31 ENode *first_edge; // 指向第一条依附该顶点的弧
  30. 32 }VNode;
  31. 33
  32. 34 // 邻接表
  33. 35 typedef struct _LGraph
  34. 36 {
  35. 37 int vexnum; // 图的顶点的数目
  36. 38 int edgnum; // 图的边的数目
  37. 39 VNode vexs[MAX];
  38. 40 }LGraph;
  39. 41
  40. 42 /*
  41. 43 * 返回ch在matrix矩阵中的位置
  42. 44 */
  43. 45 static int get_position(LGraph G, char ch)
  44. 46 {
  45. 47 int i;
  46. 48 for(i=0; i<G.vexnum; i++)
  47. 49 if(G.vexs[i].data==ch)
  48. 50 return i;
  49. 51 return -1;
  50. 52 }
  51. 53
  52. 54 /*
  53. 55 * 读取一个输入字符
  54. 56 */
  55. 57 static char read_char()
  56. 58 {
  57. 59 char ch;
  58. 60
  59. 61 do {
  60. 62 ch = getchar();
  61. 63 } while(!isLetter(ch));
  62. 64
  63. 65 return ch;
  64. 66 }
  65. 67
  66. 68 /*
  67. 69 * 将node链接到list的末尾
  68. 70 */
  69. 71 static void link_last(ENode *list, ENode *node)
  70. 72 {
  71. 73 ENode *p = list;
  72. 74
  73. 75 while(p->next_edge)
  74. 76 p = p->next_edge;
  75. 77 p->next_edge = node;
  76. 78 }
  77. 79
  78. 80 /*
  79. 81 * 创建邻接表对应的图(自己输入)
  80. 82 */
  81. 83 LGraph* create_lgraph()
  82. 84 {
  83. 85 char c1, c2;
  84. 86 int v, e;
  85. 87 int i, p1, p2;
  86. 88 int weight;
  87. 89 ENode *node1, *node2;
  88. 90 LGraph* pG;
  89. 91
  90. 92 // 输入"顶点数"和"边数"
  91. 93 printf("input vertex number: ");
  92. 94 scanf("%d", &v);
  93. 95 printf("input edge number: ");
  94. 96 scanf("%d", &e);
  95. 97 if ( v < 1 || e < 1 || (e > (v * (v-1))))
  96. 98 {
  97. 99 printf("input error: invalid parameters!\n");
  98. 100 return NULL;
  99. 101 }
  100. 102
  101. 103 if ((pG=(LGraph*)malloc(sizeof(LGraph))) == NULL )
  102. 104 return NULL;
  103. 105 memset(pG, 0, sizeof(LGraph));
  104. 106
  105. 107 // 初始化"顶点数"和"边数"
  106. 108 pG->vexnum = v;
  107. 109 pG->edgnum = e;
  108. 110 // 初始化"邻接表"的顶点
  109. 111 for(i=0; i<pG->vexnum; i++)
  110. 112 {
  111. 113 printf("vertex(%d): ", i);
  112. 114 pG->vexs[i].data = read_char();
  113. 115 pG->vexs[i].first_edge = NULL;
  114. 116 }
  115. 117
  116. 118 // 初始化"邻接表"的边
  117. 119 for(i=0; i<pG->edgnum; i++)
  118. 120 {
  119. 121 // 读取边的起始顶点,结束顶点,权
  120. 122 printf("edge(%d): ", i);
  121. 123 c1 = read_char();
  122. 124 c2 = read_char();
  123. 125 scanf("%d", &weight);
  124. 126
  125. 127 p1 = get_position(*pG, c1);
  126. 128 p2 = get_position(*pG, c2);
  127. 129
  128. 130 // 初始化node1
  129. 131 node1 = (ENode*)malloc(sizeof(ENode));
  130. 132 node1->ivex = p2;
  131. 133 node1->weight = weight;
  132. 134 // 将node1链接到"p1所在链表的末尾"
  133. 135 if(pG->vexs[p1].first_edge == NULL)
  134. 136 pG->vexs[p1].first_edge = node1;
  135. 137 else
  136. 138 link_last(pG->vexs[p1].first_edge, node1);
  137. 139 // 初始化node2
  138. 140 node2 = (ENode*)malloc(sizeof(ENode));
  139. 141 node2->ivex = p1;
  140. 142 node2->weight = weight;
  141. 143 // 将node2链接到"p2所在链表的末尾"
  142. 144 if(pG->vexs[p2].first_edge == NULL)
  143. 145 pG->vexs[p2].first_edge = node2;
  144. 146 else
  145. 147 link_last(pG->vexs[p2].first_edge, node2);
  146. 148 }
  147. 149
  148. 150 return pG;
  149. 151 }
  150. 152
  151. 153 // 边的结构体
  152. 154 typedef struct _edata
  153. 155 {
  154. 156 char start; // 边的起点
  155. 157 char end; // 边的终点
  156. 158 int weight; // 边的权重
  157. 159 }EData;
  158. 160
  159. 161 // 顶点
  160. 162 static char gVexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
  161. 163 // 边
  162. 164 static EData gEdges[] = {
  163. 165 // 起点 终点 权
  164. 166 {'A', 'B', 12},
  165. 167 {'A', 'F', 16},
  166. 168 {'A', 'G', 14},
  167. 169 {'B', 'C', 10},
  168. 170 {'B', 'F', 7},
  169. 171 {'C', 'D', 3},
  170. 172 {'C', 'E', 5},
  171. 173 {'C', 'F', 6},
  172. 174 {'D', 'E', 4},
  173. 175 {'E', 'F', 2},
  174. 176 {'E', 'G', 8},
  175. 177 {'F', 'G', 9},
  176. 178 };
  177. 179
  178. 180 /*
  179. 181 * 创建邻接表对应的图(用已提供的数据)
  180. 182 */
  181. 183 LGraph* create_example_lgraph()
  182. 184 {
  183. 185 char c1, c2;
  184. 186 int vlen = LENGTH(gVexs);
  185. 187 int elen = LENGTH(gEdges);
  186. 188 int i, p1, p2;
  187. 189 int weight;
  188. 190 ENode *node1, *node2;
  189. 191 LGraph* pG;
  190. 192
  191. 193 if ((pG=(LGraph*)malloc(sizeof(LGraph))) == NULL )
  192. 194 return NULL;
  193. 195 memset(pG, 0, sizeof(LGraph));
  194. 196
  195. 197 // 初始化"顶点数"和"边数"
  196. 198 pG->vexnum = vlen;
  197. 199 pG->edgnum = elen;
  198. 200 // 初始化"邻接表"的顶点
  199. 201 for(i=0; i<pG->vexnum; i++)
  200. 202 {
  201. 203 pG->vexs[i].data = gVexs[i];
  202. 204 pG->vexs[i].first_edge = NULL;
  203. 205 }
  204. 206
  205. 207 // 初始化"邻接表"的边
  206. 208 for(i=0; i<pG->edgnum; i++)
  207. 209 {
  208. 210 // 读取边的起始顶点,结束顶点,权
  209. 211 c1 = gEdges[i].start;
  210. 212 c2 = gEdges[i].end;
  211. 213 weight = gEdges[i].weight;
  212. 214
  213. 215 p1 = get_position(*pG, c1);
  214. 216 p2 = get_position(*pG, c2);
  215. 217
  216. 218 // 初始化node1
  217. 219 node1 = (ENode*)malloc(sizeof(ENode));
  218. 220 node1->ivex = p2;
  219. 221 node1->weight = weight;
  220. 222 // 将node1链接到"p1所在链表的末尾"
  221. 223 if(pG->vexs[p1].first_edge == NULL)
  222. 224 pG->vexs[p1].first_edge = node1;
  223. 225 else
  224. 226 link_last(pG->vexs[p1].first_edge, node1);
  225. 227 // 初始化node2
  226. 228 node2 = (ENode*)malloc(sizeof(ENode));
  227. 229 node2->ivex = p1;
  228. 230 node2->weight = weight;
  229. 231 // 将node2链接到"p2所在链表的末尾"
  230. 232 if(pG->vexs[p2].first_edge == NULL)
  231. 233 pG->vexs[p2].first_edge = node2;
  232. 234 else
  233. 235 link_last(pG->vexs[p2].first_edge, node2);
  234. 236 }
  235. 237
  236. 238 return pG;
  237. 239 }
  238. 240
  239. 241 /*
  240. 242 * 深度优先搜索遍历图的递归实现
  241. 243 */
  242. 244 static void DFS(LGraph G, int i, int *visited)
  243. 245 {
  244. 246 int w;
  245. 247 ENode *node;
  246. 248
  247. 249 visited[i] = 1;
  248. 250 printf("%c ", G.vexs[i].data);
  249. 251 node = G.vexs[i].first_edge;
  250. 252 while (node != NULL)
  251. 253 {
  252. 254 if (!visited[node->ivex])
  253. 255 DFS(G, node->ivex, visited);
  254. 256 node = node->next_edge;
  255. 257 }
  256. 258 }
  257. 259
  258. 260 /*
  259. 261 * 深度优先搜索遍历图
  260. 262 */
  261. 263 void DFSTraverse(LGraph G)
  262. 264 {
  263. 265 int i;
  264. 266 int visited[MAX]; // 顶点访问标记
  265. 267
  266. 268 // 初始化所有顶点都没有被访问
  267. 269 for (i = 0; i < G.vexnum; i++)
  268. 270 visited[i] = 0;
  269. 271
  270. 272 printf("DFS: ");
  271. 273 for (i = 0; i < G.vexnum; i++)
  272. 274 {
  273. 275 if (!visited[i])
  274. 276 DFS(G, i, visited);
  275. 277 }
  276. 278 printf("\n");
  277. 279 }
  278. 280
  279. 281 /*
  280. 282 * 广度优先搜索(类似于树的层次遍历)
  281. 283 */
  282. 284 void BFS(LGraph G)
  283. 285 {
  284. 286 int head = 0;
  285. 287 int rear = 0;
  286. 288 int queue[MAX]; // 辅组队列
  287. 289 int visited[MAX]; // 顶点访问标记
  288. 290 int i, j, k;
  289. 291 ENode *node;
  290. 292
  291. 293 for (i = 0; i < G.vexnum; i++)
  292. 294 visited[i] = 0;
  293. 295
  294. 296 printf("BFS: ");
  295. 297 for (i = 0; i < G.vexnum; i++)
  296. 298 {
  297. 299 if (!visited[i])
  298. 300 {
  299. 301 visited[i] = 1;
  300. 302 printf("%c ", G.vexs[i].data);
  301. 303 queue[rear++] = i; // 入队列
  302. 304 }
  303. 305 while (head != rear)
  304. 306 {
  305. 307 j = queue[head++]; // 出队列
  306. 308 node = G.vexs[j].first_edge;
  307. 309 while (node != NULL)
  308. 310 {
  309. 311 k = node->ivex;
  310. 312 if (!visited[k])
  311. 313 {
  312. 314 visited[k] = 1;
  313. 315 printf("%c ", G.vexs[k].data);
  314. 316 queue[rear++] = k;
  315. 317 }
  316. 318 node = node->next_edge;
  317. 319 }
  318. 320 }
  319. 321 }
  320. 322 printf("\n");
  321. 323 }
  322. 324
  323. 325 /*
  324. 326 * 打印邻接表图
  325. 327 */
  326. 328 void print_lgraph(LGraph G)
  327. 329 {
  328. 330 int i,j;
  329. 331 ENode *node;
  330. 332
  331. 333 printf("List Graph:\n");
  332. 334 for (i = 0; i < G.vexnum; i++)
  333. 335 {
  334. 336 printf("%d(%c): ", i, G.vexs[i].data);
  335. 337 node = G.vexs[i].first_edge;
  336. 338 while (node != NULL)
  337. 339 {
  338. 340 printf("%d(%c) ", node->ivex, G.vexs[node->ivex].data);
  339. 341 node = node->next_edge;
  340. 342 }
  341. 343 printf("\n");
  342. 344 }
  343. 345 }
  344. 346
  345. 347 /*
  346. 348 * 获取G中边<start, end>的权值;若start和end不是连通的,则返回无穷大。
  347. 349 */
  348. 350 int get_weight(LGraph G, int start, int end)
  349. 351 {
  350. 352 ENode *node;
  351. 353
  352. 354 if (start==end)
  353. 355 return 0;
  354. 356
  355. 357 node = G.vexs[start].first_edge;
  356. 358 while (node!=NULL)
  357. 359 {
  358. 360 if (end==node->ivex)
  359. 361 return node->weight;
  360. 362 node = node->next_edge;
  361. 363 }
  362. 364
  363. 365 return INF;
  364. 366 }
  365. 367
  366. 368 /*
  367. 369 * prim最小生成树
  368. 370 *
  369. 371 * 参数说明:
  370. 372 * G -- 邻接表图
  371. 373 * start -- 从图中的第start个元素开始,生成最小树
  372. 374 */
  373. 375 void prim(LGraph G, int start)
  374. 376 {
  375. 377 int min,i,j,k,m,n,tmp,sum;
  376. 378 int index=0; // prim最小树的索引,即prims数组的索引
  377. 379 char prims[MAX]; // prim最小树的结果数组
  378. 380 int weights[MAX]; // 顶点间边的权值
  379. 381
  380. 382 // prim最小生成树中第一个数是"图中第start个顶点",因为是从start开始的。
  381. 383 prims[index++] = G.vexs[start].data;
  382. 384
  383. 385 // 初始化"顶点的权值数组",
  384. 386 // 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。
  385. 387 for (i = 0; i < G.vexnum; i++ )
  386. 388 weights[i] = get_weight(G, start, i);
  387. 389
  388. 390 for (i = 0; i < G.vexnum; i++)
  389. 391 {
  390. 392 // 由于从start开始的,因此不需要再对第start个顶点进行处理。
  391. 393 if(start == i)
  392. 394 continue;
  393. 395
  394. 396 j = 0;
  395. 397 k = 0;
  396. 398 min = INF;
  397. 399 // 在未被加入到最小生成树的顶点中,找出权值最小的顶点。
  398. 400 while (j < G.vexnum)
  399. 401 {
  400. 402 // 若weights[j]=0,意味着"第j个节点已经被排序过"(或者说已经加入了最小生成树中)。
  401. 403 if (weights[j] != 0 && weights[j] < min)
  402. 404 {
  403. 405 min = weights[j];
  404. 406 k = j;
  405. 407 }
  406. 408 j++;
  407. 409 }
  408. 410
  409. 411 // 经过上面的处理后,在未被加入到最小生成树的顶点中,权值最小的顶点是第k个顶点。
  410. 412 // 将第k个顶点加入到最小生成树的结果数组中
  411. 413 prims[index++] = G.vexs[k].data;
  412. 414 // 将"第k个顶点的权值"标记为0,意味着第k个顶点已经排序过了(或者说已经加入了最小树结果中)。
  413. 415 weights[k] = 0;
  414. 416 // 当第k个顶点被加入到最小生成树的结果数组中之后,更新其它顶点的权值。
  415. 417 for (j = 0 ; j < G.vexnum; j++)
  416. 418 {
  417. 419 // 获取第k个顶点到第j个顶点的权值
  418. 420 tmp = get_weight(G, k, j);
  419. 421 // 当第j个节点没有被处理,并且需要更新时才被更新。
  420. 422 if (weights[j] != 0 && tmp < weights[j])
  421. 423 weights[j] = tmp;
  422. 424 }
  423. 425 }
  424. 426
  425. 427 // 计算最小生成树的权值
  426. 428 sum = 0;
  427. 429 for (i = 1; i < index; i++)
  428. 430 {
  429. 431 min = INF;
  430. 432 // 获取prims[i]在G中的位置
  431. 433 n = get_position(G, prims[i]);
  432. 434 // 在vexs[0...i]中,找出到j的权值最小的顶点。
  433. 435 for (j = 0; j < i; j++)
  434. 436 {
  435. 437 m = get_position(G, prims[j]);
  436. 438 tmp = get_weight(G, m, n);
  437. 439 if (tmp < min)
  438. 440 min = tmp;
  439. 441 }
  440. 442 sum += min;
  441. 443 }
  442. 444 // 打印最小生成树
  443. 445 printf("PRIM(%c)=%d: ", G.vexs[start].data, sum);
  444. 446 for (i = 0; i < index; i++)
  445. 447 printf("%c ", prims[i]);
  446. 448 printf("\n");
  447. 449 }
  448. 450
  449. 451 /*
  450. 452 * 获取图中的边
  451. 453 */
  452. 454 EData* get_edges(LGraph G)
  453. 455 {
  454. 456 int i,j;
  455. 457 int index=0;
  456. 458 ENode *node;
  457. 459 EData *edges;
  458. 460
  459. 461 edges = (EData*)malloc(G.edgnum*sizeof(EData));
  460. 462 for (i=0; i<G.vexnum; i++)
  461. 463 {
  462. 464 node = G.vexs[i].first_edge;
  463. 465 while (node != NULL)
  464. 466 {
  465. 467 if (node->ivex > i)
  466. 468 {
  467. 469 edges[index].start = G.vexs[i].data; // 起点
  468. 470 edges[index].end = G.vexs[node->ivex].data; // 终点
  469. 471 edges[index].weight = node->weight; // 权
  470. 472 index++;
  471. 473 }
  472. 474 node = node->next_edge;
  473. 475 }
  474. 476 }
  475. 477
  476. 478 return edges;
  477. 479 }
  478. 480
  479. 481 /*
  480. 482 * 对边按照权值大小进行排序(由小到大)
  481. 483 */
  482. 484 void sorted_edges(EData* edges, int elen)
  483. 485 {
  484. 486 int i,j;
  485. 487
  486. 488 for (i=0; i<elen; i++)
  487. 489 {
  488. 490 for (j=i+1; j<elen; j++)
  489. 491 {
  490. 492 if (edges[i].weight > edges[j].weight)
  491. 493 {
  492. 494 // 交换"第i条边"和"第j条边"
  493. 495 EData tmp = edges[i];
  494. 496 edges[i] = edges[j];
  495. 497 edges[j] = tmp;
  496. 498 }
  497. 499 }
  498. 500 }
  499. 501 }
  500. 502
  501. 503 /*
  502. 504 * 获取i的终点
  503. 505 */
  504. 506 int get_end(int vends[], int i)
  505. 507 {
  506. 508 while (vends[i] != 0)
  507. 509 i = vends[i];
  508. 510 return i;
  509. 511 }
  510. 512
  511. 513 /*
  512. 514 * 克鲁斯卡尔(Kruskal)最小生成树
  513. 515 */
  514. 516 void kruskal(LGraph G)
  515. 517 {
  516. 518 int i,m,n,p1,p2;
  517. 519 int length;
  518. 520 int index = 0; // rets数组的索引
  519. 521 int vends[MAX]={0}; // 用于保存"已有最小生成树"中每个顶点在该最小树中的终点。
  520. 522 EData rets[MAX]; // 结果数组,保存kruskal最小生成树的边
  521. 523 EData *edges; // 图对应的所有边
  522. 524
  523. 525 // 获取"图中所有的边"
  524. 526 edges = get_edges(G);
  525. 527 // 将边按照"权"的大小进行排序(从小到大)
  526. 528 sorted_edges(edges, G.edgnum);
  527. 529
  528. 530 for (i=0; i<G.edgnum; i++)
  529. 531 {
  530. 532 p1 = get_position(G, edges[i].start); // 获取第i条边的"起点"的序号
  531. 533 p2 = get_position(G, edges[i].end); // 获取第i条边的"终点"的序号
  532. 534
  533. 535 m = get_end(vends, p1); // 获取p1在"已有的最小生成树"中的终点
  534. 536 n = get_end(vends, p2); // 获取p2在"已有的最小生成树"中的终点
  535. 537 // 如果m!=n,意味着"边i"与"已经添加到最小生成树中的顶点"没有形成环路
  536. 538 if (m != n)
  537. 539 {
  538. 540 vends[m] = n; // 设置m在"已有的最小生成树"中的终点为n
  539. 541 rets[index++] = edges[i]; // 保存结果
  540. 542 }
  541. 543 }
  542. 544 free(edges);
  543. 545
  544. 546 // 统计并打印"kruskal最小生成树"的信息
  545. 547 length = 0;
  546. 548 for (i = 0; i < index; i++)
  547. 549 length += rets[i].weight;
  548. 550 printf("Kruskal=%d: ", length);
  549. 551 for (i = 0; i < index; i++)
  550. 552 printf("(%c,%c) ", rets[i].start, rets[i].end);
  551. 553 printf("\n");
  552. 554 }
  553. 555
  554. 556 /*
  555. 557 * Dijkstra最短路径。
  556. 558 * 即,统计图(G)中"顶点vs"到其它各个顶点的最短路径。
  557. 559 *
  558. 560 * 参数说明:
  559. 561 * G -- 图
  560. 562 * vs -- 起始顶点(start vertex)。即计算"顶点vs"到其它顶点的最短路径。
  561. 563 * prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
  562. 564 * dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。
  563. 565 */
  564. 566 void dijkstra(LGraph G, int vs, int prev[], int dist[])
  565. 567 {
  566. 568 int i,j,k;
  567. 569 int min;
  568. 570 int tmp;
  569. 571 int flag[MAX]; // flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。
  570. 572
  571. 573 // 初始化
  572. 574 for (i = 0; i < G.vexnum; i++)
  573. 575 {
  574. 576 flag[i] = 0; // 顶点i的最短路径还没获取到。
  575. 577 prev[i] = 0; // 顶点i的前驱顶点为0。
  576. 578 dist[i] = get_weight(G, vs, i); // 顶点i的最短路径为"顶点vs"到"顶点i"的权。
  577. 579 }
  578. 580
  579. 581 // 对"顶点vs"自身进行初始化
  580. 582 flag[vs] = 1;
  581. 583 dist[vs] = 0;
  582. 584
  583. 585 // 遍历G.vexnum-1次;每次找出一个顶点的最短路径。
  584. 586 for (i = 1; i < G.vexnum; i++)
  585. 587 {
  586. 588 // 寻找当前最小的路径;
  587. 589 // 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。
  588. 590 min = INF;
  589. 591 for (j = 0; j < G.vexnum; j++)
  590. 592 {
  591. 593 if (flag[j]==0 && dist[j]<min)
  592. 594 {
  593. 595 min = dist[j];
  594. 596 k = j;
  595. 597 }
  596. 598 }
  597. 599 // 标记"顶点k"为已经获取到最短路径
  598. 600 flag[k] = 1;
  599. 601
  600. 602 // 修正当前最短路径和前驱顶点
  601. 603 // 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。
  602. 604 for (j = 0; j < G.vexnum; j++)
  603. 605 {
  604. 606 tmp = get_weight(G, k, j);
  605. 607 tmp = (tmp==INF ? INF : (min + tmp)); // 防止溢出
  606. 608 if (flag[j] == 0 && (tmp < dist[j]) )
  607. 609 {
  608. 610 dist[j] = tmp;
  609. 611 prev[j] = k;
  610. 612 }
  611. 613 }
  612. 614 }
  613. 615
  614. 616 // 打印dijkstra最短路径的结果
  615. 617 printf("dijkstra(%c): \n", G.vexs[vs].data);
  616. 618 for (i = 0; i < G.vexnum; i++)
  617. 619 printf(" shortest(%c, %c)=%d\n", G.vexs[vs].data, G.vexs[i].data, dist[i]);
  618. 620 }
  619. 621
  620. 622 void main()
  621. 623 {
  622. 624 int prev[MAX] = {0};
  623. 625 int dist[MAX] = {0};
  624. 626 LGraph* pG;
  625. 627
  626. 628 // 自定义"图"(自己输入数据)
  627. 629 //pG = create_lgraph();
  628. 630 // 采用已有的"图"
  629. 631 pG = create_example_lgraph();
  630. 632
  631. 633 //print_lgraph(*pG); // 打印图
  632. 634 //DFSTraverse(*pG); // 深度优先遍历
  633. 635 //BFS(*pG); // 广度优先遍历
  634. 636 //prim(*pG, 0); // prim算法生成最小生成树
  635. 637 //kruskal(*pG); // kruskal算法生成最小生成树
  636. 638
  637. 639 // dijkstra算法获取"第4个顶点"到其它各个顶点的最短距离
  638. 640 dijkstra(*pG, 3, prev, dist);
  639. 641 }

图的全部实现(邻接矩阵 邻接表 BFS DFS 最小生成树 最短路径等)的更多相关文章

  1. 数据结构学习笔记05图 (邻接矩阵 邻接表-->BFS DFS、最短路径)

    数据结构之图 图(Graph) 包含 一组顶点:通常用V (Vertex) 表示顶点集合 一组边:通常用E (Edge) 表示边的集合 边是顶点对:(v, w) ∈E ,其中v, w ∈ V 有向边& ...

  2. PAT1013. Battle Over Cities(邻接矩阵、邻接表分别dfs)

    //采用不同的图存储结构结构邻接矩阵.邻接表分别dfs,我想我是寂寞了吧,应该试试并查集,看见可以用并查集的就用dfs,bfs代替......怕了并查集了 //邻接矩阵dfs #include< ...

  3. 网络流三大算法【邻接矩阵+邻接表】POJ1273

    网络流的基本概念跟算法原理我是在以下两篇博客里看懂的,写的非常好. http://www.cnblogs.com/ZJUT-jiangnan/p/3632525.html http://www.cnb ...

  4. 【数据结构】【图文】【oj习题】 图的拓扑排序(邻接表)

    拓扑排序: 按照有向图给出的次序关系,将图中顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系,由此所得顶点的线性序列称之为拓扑有序序列.显然对于有回路的有向图得不 ...

  5. 图的基本遍历算法的实现(BFS & DFS)复习

    #include <stdio.h> #define INF 32767 typedef struct MGraph{ ]; ][]; int ver_num, edge_num; }MG ...

  6. 第6章 图的学习总结(邻接矩阵&邻接表)

    我觉得图这一章的学习内容更有难度,其实图可以说是树结构更为普通的表现形式,它的每个元素都可以与多个元素之间相关联,所以结构比树更复杂,然而越复杂的数据结构在现实中用途就越大了,功能与用途密切联系,所以 ...

  7. 图结构练习——BFS——从起始点到目标点的最短步数(邻接表+BFS)

    图练习-BFS-从起点到目标点的最短步数 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描写叙述 在古老的魔兽传说中.有两个军团,一个 ...

  8. 图的基本操作(基于邻接表):图的构造,深搜(DFS),广搜(BFS)

    #include <iostream> #include <string> #include <queue> using namespace std; //表结点 ...

  9. ACM/ICPC 之 数据结构-邻接表+BFS(TSH OJ-无线广播Broadcast)

    这道题中若能够构成互不干扰的区域,其构成的图其实就是汉密尔顿路(Hamilton road),因此如果能够观察出来可以直接转化为汉密尔顿路的存在性证明,即便不能观察,我相信ACMer也能转化为BFS问 ...

随机推荐

  1. Dledger的是如何实现主从自动切换的

    前言 hello小伙伴们,今天王子又来继续和大家聊RocketMQ了,之前的文章我们一直说Broker的主从切换是可以基于Dledger实现自动切换的,那么小伙伴们是不是很好奇它究竟是如何实现的呢?今 ...

  2. React代码开发规范

    前言 一般在团队开发中每个人的代码习惯都不太一样,这样就会导致代码风格不一致,以致于维护和修改bug的时候看别人的代码成为一种痛苦...这种情况尤其在前端开发中尤为明显.因为关于前端的开发规范貌似也没 ...

  3. 你在开发过程中使用Git Rebase还是Git Merge?

    摘要:在git里面经常的一个争论是到底用rebase还是用merge? 1. 痛苦吗?代码历史中的迷失羔羊 我们先来看一个真实的代码提交历史图形化截图: 图片源自 https://storage.kr ...

  4. vs工程生成dll文件及其调用方法

    转载:https://blog.csdn.net/weixin_44536482/article/details/91519413 vs工程生成dll文件及其调用方法                  ...

  5. AD(Altium Designer)PCB布线中的“格式刷”,助力快速布局布线

    摘要:在AD(Altium Designer)进行电路板布线时,孔丙火(微信公众号:孔丙火)经常会碰到电路中有相同功能的模块,比如2路相同的RS485通信电路.多路相同继电器输出电路.多路相同的输入电 ...

  6. shell-的变量-局部变量

    1. 定义本地变量 本地变量在用户当前的shell生产期的脚本中使用.例如,本地变量OLDBOY取值为ett098,这个值只在用户当前shell生存期中有意义.如果在shell中启动另一个进程或退出, ...

  7. .NET Standard 类库的使用技巧

    系列目录     [已更新最新开发文章,点击查看详细] 在前一篇博客<.NET Standard中配置TargetFrameworks输出多版本类库>中详细介绍了如何创建.配置.条件编译. ...

  8. Cypress系列(63)- 使用 Custom Commands

    如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html Custom Commands 自定义命 ...

  9. 网站搭建-云服务器ECS的使用

    1. 查看购买的云服务器实例,重置密码 2. 查找IP进行查看,此时网页时不存在的,开始配置: 3. 登录putty或其他终端,进行网页搭建,先按教程走一遍,然后再做个性化处理: #安装Apache ...

  10. 2016年 实验五 Internet与网络工具的使用

    实验五 Internet与网络工具的使用 [实验目的] 本实验目的在于掌握 Telnet.FTP.Email的工作机理,并会在 Internet 上熟练使用相关工具软件. [实验条件] ⑴.个人计算机 ...