1. 程式人生 > >最小生成樹與最短路徑--C語言實現

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

的區別 find 延遲 遍歷 最短路徑 標記 += 創建 png

接昨天,在這裏給出圖的其中一種應用:最小生成樹算法(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沒調好,所以要延遲一天,勿怪。

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