最小生成樹與最短路徑--C語言實現


接昨天,在這里給出圖的其中一種應用:最小生成樹算法(Prime算法Kruskal算法)。兩種算法的區別就是:Prime算法以頂點為主線適合用於頂點少,邊密集的圖結構Kruskal算法以邊為主線適合於頂點比較多,但是邊比較稀疏的圖結構。代碼如下,親測,可執行,在最后也給出輸入數據的形式。

 1 /*
 2 圖結構的最小生成樹算法:  3  1.prime算法:按頂點查找,遍歷當前頂點所有鄰接邊,選擇權值最小值,  4  記錄這兩個頂點,直到所有的頂點都已處理  5 
 6  2.Kruskal算法:按邊查找,將所有邊的權值排序,以此選擇權值最小的邊,  7  檢查該邊連接的兩個頂點是否狀態一致(都已處理,或都未處理),  8  直到所有頂點都標記為處理過  9 */
 10 
 11 
 12 #include<stdio.h>
 13 #define INFINITY 65535
 14 #define MAXVEX 100
 15 
 16 //邊集數組圖結構
 17 typedef struct                        //邊結構體
 18 {  19     int start;  20     int end;  21     int weight;  22 }Edges;  23 
 24 typedef struct                        //圖結構
 25 {  26     char Vex[MAXVEX];                //頂點數組
 27     Edges edge[MAXVEX];                //邊數組
 28     int numVexes;                    //頂點數量
 29     int numEdges;                    //邊數量
 30 }E_VGraph;  31 
 32 //鄰接矩陣圖結構
 33 typedef struct
 34 {  35     char Vex[MAXVEX];                //頂點數組
 36     int arc[MAXVEX][MAXVEX];        //邊數組
 37     int numVexes;                    //頂點數量
 38     int numEdges;                    //邊數量
 39 }Graph;  40 
 41 //鄰接矩陣圖結構轉化為邊集數組圖結構,並將權值升序排序
 42 void G_EVConversion(Graph G, E_VGraph *G1)  43 {  44     int i,j,k,lowest;  45  Edges edges[MAXVEX];  46     G1->numVexes = G.numVexes;                    //將鄰接矩陣頂點數賦值於邊集數組
 47     G1->numEdges = G.numEdges;                    //將鄰接矩陣邊數賦值於邊集數組
 48     for(i = 0; i < G.numVexes; i++)                //遍歷鄰接矩陣中的每個頂點
 49  {  50         for(j = i+1; j < G.numVexes; j++)        //遍歷除當前結點之后的結點
 51  {  52             if(G.arc[i][j] != INFINITY)            //判斷兩頂點之間是否有邊
 53  {  54                 edges[i].start = i;            //記錄當前邊的起點
 55                 edges[i].end = j;            //記錄當前邊的終點
 56                 edges[i].weight = G.arc[i][j];    //記錄當前邊的權重
 57                 printf("%d %d\n",G.arc[i][j],edges[i].weight);  58  }  59  }  60  }  61     printf("\n\n");  62     for(i = 0; i < G.numEdges; i++)            //選擇排序edges數組
 63  {  64         lowest = INFINITY;  65         for(j = 0; j < G.numEdges; j++)  66  {  67             printf("%d %d %d\n",j,edges[j].weight,lowest);  68             if(edges[j].weight <= lowest)  69  {  70                 lowest = edges[j].weight;  71                 k = j;  72                 printf("\n%d\n",k);  73  }  74  }  75         G1->edge[i].start = edges[k].start;        //將每輪找出的最小權值的邊的信息
 76         G1->edge[i].end = edges[k].end;            //寫入邊集數組中
 77         G1->edge[i].weight = edges[k].weight;  78         edges[k].weight = INFINITY;                //賦值完畢,將此最小權值設為最大值
 79         printf("\n");  80         printf("%d\n",G1->edge[i].weight);  81  }  82 }  83 
 84 //確認函數
 85 int Find(int *parent, int f)  86 {  87     if(parent[f] > 0)            //檢查此頂點是否處理過,若大於0,則處理過
 88         f = parent[f];            //將parent[f]的值賦值給f
 89     return f;                    //返回f
 90 }  91 
 92 //克魯斯卡爾算法構造最小生成樹
 93 void minTreeKruskal(E_VGraph G1)  94 {  95     int i,j,k,w,n,m;  96     int parent[MAXVEX];                    //記錄結點狀態
 97     int lowest = 0;                            //最小權值
 98     for(i = 0; i < G1.numVexes; i++)    //初始化記錄數組,所有頂點記為未被處理
 99         parent[i] = 0; 100     for(i = 0; i < G1.numEdges; i++)    //遍歷邊集數組
101  { 102         n = Find(parent, G1.edge[i].start);    //得到當前邊的開始頂點的狀態
103         m = Find(parent, G1.edge[i].end);        //得到當前邊的結束頂點的狀態
104         if(n != m)                                //若狀態不同(即,起點與終點一個處理過,一個未處理)
105  { 106             lowest += G1.edge[i].weight;        //將此邊的權值加入最小生成樹權值
107             parent[G1.edge[i].start] = 1;        //將起點記為處理過
108             parent[G1.edge[i].end] = 1;            //將終點記為處理過
109  } 110  } 111     printf("克魯斯卡爾算法構建最小生成樹的權值為:%d\n", lowest); 112 } 113 
114 
115 
116 void CreatGraph(Graph *G)            //創建圖結構
117 { 118     int i,j,k,w,a[100]; 119     printf("請輸入頂點與邊的數量:"); 120     scanf("%d,%d",&G->numVexes,&G->numEdges);        //寫入頂點數量與邊的數量
121     for(i = 0; i < G->numVexes; i++)                //初始化頂點數組
122  { 123         printf("請輸入第%d個頂點:", i); 124         scanf("%c",&G->Vex[i]); 125  getchar(); 126  } 127     for(i = 0; i < G->numVexes; i++)                //初始化邊數組
128         for(j = 0; j < G->numVexes; j++) 129             G->arc[i][j] = INFINITY; 130     
131     for(k = 0; k < G->numEdges; k++)                //構造邊的數組
132  { 133         printf("請輸入邊的起點與終點的下標及其權重:"); 134         scanf("%d,%d,%d",&i,&j,&w); 135         G->arc[i][j] = G->arc[j][i] = w;            //無向圖的對稱性
136  } 137     printf("創建成功\n"); 138 } 139 
140 //Prim算法構造最小生成樹
141 void minTreePrim(Graph G,int i) 142 { 143     int j,k,l,w,count,zongWeight; 144     int visited[MAXVEX];                //記錄訪問過的頂點
145     int lowest[MAXVEX];                    //記錄最小權值
146     for(j = 0; j < G.numVexes; j++)        //初始化訪問數組,將所有頂點記為未訪問過
147         visited[j] = 0; 148     visited[i] = 1;                        //將傳入頂點記為訪問過
149     lowest[i] = 0;                        //將此頂點的權值記為0
150     zongWeight = 0;                        //總權重為0
151     count = 1;                            //訪問過的頂點數量為1
152     int wei = INFINITY;                    //權重變量記為最大值
153     while(count < G.numVexes)            //只要訪問過的頂點數目小於圖中頂點數目,繼續循環
154  { 155         for(k = 0; k < G.numVexes; k++)    //遍歷訪問過的頂點數組
156  { 157             if(visited[k] == 1)            //如果當前頂點訪問了,尋找它的鄰接邊
158  { 159                 for(l = 0; l < G.numVexes; l++)        //遍歷圖中所有頂點
160  { 161                     if(visited[l] == 0 && G.arc[k][l] < wei)    //如果未被訪問,且權值小於權值變量
162  { 163                         wei = G.arc[k][l];            //更新權值變量
164                         w = l;                        //更新最小頂點
165  } 166  } 167  } 168  } 169         visited[w] = 1;                    //將最小權值頂點記為訪問過
170         lowest[l] = wei;                //記錄他的權值
171         zongWeight += wei;                //加入總權重
172         count++;                        //訪問過的頂點數量+1
173         wei = INFINITY; 174 
175  } 176     printf("最小生成樹的權值為:%d\n",zongWeight); 177 } 178 
179 void main() 180 { 181  Graph G; 182  E_VGraph G1; 183     
184     printf("請構造圖結構:\n"); 185     CreatGraph(&G); 186 
187     printf("\n\n"); 188     printf("普利姆算法構建最小生成樹\n"); 189     minTreePrim(G,0); 190     
191     printf("\n\n"); 192     printf("克魯斯卡爾算法構建最小生成樹\n"); 193     G_EVConversion(G, &G1); 194  minTreeKruskal(G1); 195 }

本來今天應該將最小生成樹與最短路徑的算法一起上傳,但是我寫的最短路徑算法還有一些bug沒調好,所以要延遲一天,勿怪。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM