Dijkstra算法 (轉)寫的特別好~

========================================================================

       這主要是用來找起點與終點最短路徑的方法,搜索是以目標節點全遍歷的方式進行搜索,一步步確定每個節點的最短路徑才終止.

       操作過程中分兩集合:  確定最短路徑頂點集合U 與 未確定最短路徑頂點集合V.  利用U裏面的有向向量鏈分別搜索V裏面的每個節點,形成的最短鏈對應的那個節點就可以確定最短路徑了,其就可以加入集合U,逐步搜索整個集合V,直到V中數量減小到零,全部確定.

======================================================================== 

   先上基本搜索步驟圖對算法理解.轉自:圖之Dijkstra算法   

   圖之Dijkstra算法

     Dijkstra算法是一種求單源最短路算法,即從一個點開始到所有其他點的最短路。其步驟如下: (原文鏈接有參考代碼.)


1

2
 

3

4
 

5

6
 


    既然理解了搜索步驟,那我們看看其中的思想.  參見:最短路徑之Dijkstra算法詳細講解

最短路徑之Dijkstra算法詳細講解

1  最短路徑算法

在日常生活中,我們如果需要常常往返A地區和B地區之間,我們最希望知道的可能是從A地區到B地區間的衆多路徑中,那一條路徑的路途最短。最短路徑問題是圖論研究中的一個經典算法問題, 旨在尋找圖(由結點和路徑組成的)中兩結點之間的最短路徑。 算法具體的形式包括:

(1)確定起點的最短路徑問題:即已知起始結點,求最短路徑的問題。

(2)確定終點的最短路徑問題:與確定起點的問題相反,該問題是已知終結結點,求最短路徑的問題。在無向圖中該問題與確定起點的問題完全等同,在有向圖中該問題等同於把所有路徑方向反轉的確定起點的問題。

(3)確定起點終點的最短路徑問題:即已知起點和終點,求兩結點之間的最短路徑。

(4)全局最短路徑問題:求圖中所有的最短路徑。

用於解決最短路徑問題的算法被稱做“最短路徑算法”, 有時被簡稱作“路徑算法”。 最常用的路徑算法有:Dijkstra算法、A*算法、Bellman-Ford算法、Floyd-Warshall算法、Johnson算法。 

2  Dijkstra算法

2.1  Dijkstra算法

  Dijkstra算法是典型最短路算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點爲中心向外層層擴展,直到擴展到終點爲止。Dijkstra算法能得出最短路徑的最優解,但由於它遍歷計算的節點很多,所以效率低

Dijkstra算法是很有代表性的最短路算法,在很多專業課程中都作爲基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。 

2.2  Dijkstra算法思想

Dijkstra算法思想爲:

           設G=(V,E)是一個帶權有向圖,把圖中頂點集合V分成兩組,

         第一組爲已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以後每求得一條最短路徑 , 就將 加入到集合S中,直到全部頂點都加入到S中,算法就結束了),

          第二組爲其餘未確定最短路徑的頂點集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大於從源點v到U中任何頂點的最短路徑長度。

            此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點爲中間頂點的當前最短路徑長度。

2.3  Dijkstra算法具體步驟  

1)初始時,S只包含源點,即S=,v的距離爲0。U包含除v外的其他頂點,U中頂點u距離爲邊上的權(若v與u有邊)或 )(若u不是v的出邊鄰接點)。

(2)從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

(3)以k爲新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。

(4)重複步驟(2)和(3)直到所有頂點都包含在S中。

2.4  Dijkstra算法舉例說明

如下圖,設A爲源點,求A到其他各頂點(B、C、D、E、F)的最短路徑。線上所標註爲相鄰線段之間的距離,即權值。(注:此圖爲隨意所畫,其相鄰頂點間的距離與圖中的目視長度不能一一對等)

圖一:Dijkstra無向圖

 最短路徑之Dijkstra算法詳細講解 - 綠巖 - 永遠的綠巖

算法執行步驟如下表:【注:圖片要是看不到請到“相冊--日誌相冊”中,名爲“Dijkstra算法過程”的圖就是了】



=========================  轉自最短路徑之Dijkstra算法 =========================

dijkstra算法兩個應用題:

HDOJ 1874 暢通工程續,現有解法:www.wutianqi.com/?p=1894
HDOJ 2544 最短路,現有解法:www.wutianqi.com/?p=1892

參考:http://hi.baidu.com/zealot886/item/c8a499ee5795bcddeb34c950

           數據結構(C語言版)

          http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html

推薦幾篇搜索算法相關的非常好的博文:

一、A*搜索算法

一(續)、A*,Dijkstra,BFS算法性能比較及A*算法的應用

二、Dijkstra 算法初探          (Dijkstra算法系列4篇文章)

二(續)、徹底理解Dijkstra算法

二(再續)、Dijkstra 算法+fibonacci堆的逐步c實現

二(三續)、Dijkstra 算法+Heap堆的完整c實現源碼



==============

代碼

 

[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <malloc.h>  
  3. #define VERTEXNUM 6  
  4.   
  5. //存放最短路徑的邊元素  
  6. typedef struct edge{  
  7.         int vertex;  
  8.         int value;  
  9.         struct edge* next;  
  10. }st_edge;  
  11.   
  12. void createGraph(int (*edge)[VERTEXNUM], int start, int end, int value);  
  13. void displayGraph(int (*edge)[VERTEXNUM]);  
  14. void displayPath(st_edge** path, int startVertex,int* shortestPath);  
  15. void dijkstra(int (*edge)[VERTEXNUM], st_edge*** path, int** shortestPath, int startVertex, int* vertexStatusArr);  
  16. int getDistance(int value, int startVertex, int start, int* shortestPath);  
  17. void createPath(st_edge **path, int startVertex, int start, int end, int edgeValue);  
  18.   
  19. int main(void){  
  20.         //動態創建存放邊的二維數組  
  21.         int (*edge)[VERTEXNUM] = (int (*)[VERTEXNUM])malloc(sizeof(int)*VERTEXNUM*VERTEXNUM);  
  22.         int i,j;  
  23.         for(i=0;i<VERTEXNUM;i++){  
  24.                 for(j=0;j<VERTEXNUM;j++){  
  25.                         edge[i][j] = 0;  
  26.                 }  
  27.         }  
  28.         //存放頂點的遍歷狀態,0:未遍歷,1:已遍歷  
  29.         int* vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM);  
  30.         for(i=0;i<VERTEXNUM;i++){  
  31.                 vertexStatusArr[i] = 0;  
  32.         }  
  33.   
  34.         printf("after init:\n");  
  35.         displayGraph(edge);  
  36.         //創建圖  
  37.         createGraph(edge,0,1,6);  
  38.         createGraph(edge,0,3,5);  
  39.         createGraph(edge,0,2,1);  
  40.         createGraph(edge,1,2,5);  
  41.         createGraph(edge,1,4,3);  
  42.         createGraph(edge,2,4,6);  
  43.         createGraph(edge,2,3,5);  
  44.         createGraph(edge,2,5,4);  
  45.         createGraph(edge,3,5,2);  
  46.         createGraph(edge,4,5,6);  
  47.   
  48.         printf("after create:\n");  
  49.         displayGraph(edge);  
  50.     //最短路徑  
  51.         /*存儲的結構如下: 
  52.             path[0]:edge0->NULL 
  53.             path[1]:edge1->NULL 
  54.             path[2]:edge1->edge2->NULL 
  55.             path[3]:edge1->edge2->edge3->NULL 
  56.             path[4]:edge4->NULL 
  57.             從頂點0到0的最短路徑:從0出發直接到0 
  58.             從頂點0到1的最短路徑:從0出發直接到1 
  59.             從頂點0到2的最短路徑:從0出發到1,從1出發到2 
  60.             ...... 
  61.         */  
  62.     st_edge** path = NULL;  
  63.     //存儲最短路徑的權值  
  64.         /* 
  65.         shortestPath[0] = 0; 
  66.         shortestPath[1] = 8; 
  67.         shortestPath[2] = 12; 
  68.         從頂點0到0的路徑是0 
  69.         從頂點0到1的路徑是8 
  70.         從頂點0到2的路徑是12 
  71.         */  
  72.     int* shortestPath = NULL;  
  73.     //從頂點0開始尋找最短路徑  
  74.     int startVertex = 0;  
  75.     //最短路徑  
  76.     dijkstra(edge, &path, &shortestPath, startVertex, vertexStatusArr);  
  77.     printf("the path is:\n");  
  78.     displayPath(path,startVertex,shortestPath);  
  79.   
  80.         free(edge);  
  81.         free(path);  
  82.         return 0;  
  83. }  
  84. //創建圖  
  85. void createGraph(int (*edge)[VERTEXNUM], int start, int end, int value){  
  86.         edge[start][end] = value;  
  87.         edge[end][start] = value;  
  88. }  
  89. //打印存儲的圖  
  90. void displayGraph(int (*edge)[VERTEXNUM]){  
  91.         int i,j;  
  92.         for(i=0;i<VERTEXNUM;i++){  
  93.                 for(j=0;j<VERTEXNUM;j++){  
  94.                         printf("%d ",edge[i][j]);  
  95.                 }  
  96.                 printf("\n");  
  97.         }  
  98. }  
  99. //打印最短路徑  
  100. void displayPath(st_edge** path, int startVertex,int* shortestPath){  
  101.         int i;  
  102.         st_edge* p;  
  103.         for(i=0;i<VERTEXNUM;i++){  
  104.                 printf("Path from %d to %d:",startVertex,i);  
  105.                 p = *(path+i);  
  106.                 while(p != NULL){  
  107.                         printf("%d(%d) ",p->vertex,p->value);  
  108.                         p = p->next;  
  109.                 }  
  110.                 printf("\n");  
  111.         printf("the count is:%d\n",shortestPath[i]);  
  112.         }  
  113. }  
  114. //最短路徑  
  115. void dijkstra(int (*edge)[VERTEXNUM], st_edge*** path, int** shortestPath, int startVertex, int* vertexStatusArr){  
  116.     //初始化最短路徑  
  117.     *path = (st_edge**)malloc(sizeof(st_edge*)*VERTEXNUM);  
  118.         int i,j;  
  119.     for(i=0;i<VERTEXNUM;i++){  
  120.         if(i == startVertex){  
  121.             st_edge* e = (st_edge*)malloc(sizeof(st_edge));  
  122.             e->vertex = startVertex;  
  123.             e->value = 0;  
  124.             e->next = NULL;  
  125.             (*path)[i] = e;  
  126.         }else{  
  127.             (*path)[i] = NULL;  
  128.         }  
  129.     }  
  130.     //初始化最短路徑的權值  
  131.     *shortestPath = (int *)malloc(sizeof(int)*VERTEXNUM);  
  132.     for(i=0;i<VERTEXNUM;i++){  
  133.         if(i == startVertex){  
  134.             (*shortestPath)[i] = 0;  
  135.         }else{  
  136.             (*shortestPath)[i] = -1;  
  137.         }  
  138.     }  
  139.     //從頂點0開始,則頂點0就是已訪問的  
  140.     vertexStatusArr[startVertex] = 1;  
  141.   
  142.     int shortest, distance,start, end, edgeValue, vNum = 1;  
  143.         //如果還頂點還沒有訪問完  
  144.         while(vNum < VERTEXNUM){  
  145.                 shortest = 9999;  
  146.                 for(i=0;i<VERTEXNUM;i++){  
  147.                         //選擇已經訪問過的點  
  148.                         if(vertexStatusArr[i] == 1){  
  149.                                 for(j=0;j<VERTEXNUM;j++){  
  150.                                         //選擇一個沒有訪問過的點  
  151.                                         if(vertexStatusArr[j] == 0){  
  152.                                                 //選出一條value最小的邊  
  153.                                                 if(edge[i][j] != 0 && (distance = getDistance(edge[i][j], startVertex, i,  *shortestPath)) < shortest){  
  154.                                                         shortest = distance;  
  155.                                                         edgeValue = edge[i][j];  
  156.                                                         start = i;  
  157.                                                         end = j;  
  158.                                                 }  
  159.                                         }  
  160.                                 }  
  161.                         }  
  162.                 }  
  163.                 vNum++;  
  164.             //將點設置爲訪問過  
  165.             vertexStatusArr[end] = 1;  
  166.             //保存最短路徑權值  
  167.             (*shortestPath)[end] = shortest;  
  168.             //保存最短路徑  
  169.             createPath(*path, startVertex, start, end, edgeValue);  
  170.         }  
  171. }  
  172.   
  173. //返回從startVertex到新的頂點的距離  
  174. int getDistance(int value, int startVertex, int start, int* shortestPath){  
  175.     if(start == startVertex){  
  176.         return value;  
  177.     }else{  
  178.         return shortestPath[start] + value;  
  179.     }  
  180. }  
  181.   
  182. //保存最短路徑  
  183. void createPath(st_edge **path, int startVertex, int start, int end, int edgeValue){  
  184.     if(start == startVertex){  
  185.         st_edge* newEdge = (st_edge*)malloc(sizeof(st_edge));  
  186.         newEdge->vertex = end;  
  187.         newEdge->value = edgeValue;  
  188.         newEdge->next = NULL;  
  189.   
  190.         st_edge** p = path + end;  
  191.         while((*p) != NULL){  
  192.             p = &((*p)->next);  
  193.         }  
  194.         *p = newEdge;  
  195.     }else{  
  196.         st_edge** pCopySrc = path + start;  
  197.         st_edge** pCopyDes = path + end;  
  198.         st_edge* newEdge = NULL;  
  199.         while((*pCopySrc) != NULL){  
  200.             newEdge = (st_edge*)malloc(sizeof(st_edge));  
  201.             *newEdge = **pCopySrc;  
  202.             newEdge->next = NULL;  
  203.             *pCopyDes = newEdge;  
  204.             pCopySrc = &((*pCopySrc)->next);  
  205.             pCopyDes = &((*pCopyDes)->next);  
  206.         }  
  207.         newEdge = (st_edge*)malloc(sizeof(st_edge));  
  208.         newEdge->vertex = end;  
  209.         newEdge->value = edgeValue;  
  210.         newEdge->next = NULL;  
  211.         *pCopyDes = newEdge;  
  212.     }  
  213. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章