參考資料:
http://blog.csdn.net/yeruby/article/details/38615045
prim算法不太好理解,在這里記錄一下:
2個數組的解釋
adjvex[i]:表示對應lowcost[i]的起點
lowcost[i]:表示以i為終點的邊的最小權值,當lowcost[i]=0說明以i為終點的邊的最小權值=0
如:adjex[2] = 1,lowcast[2] = 6; 表示 頂點 1 到頂點2 的距離 是 6;
C語言實現代碼(無向矩陣):
#include <stdio.h>
#include <stdlib.h>
#define MAX_LENGTH 100
#define INFINITY 65536 // 表示無邊連接
#define NO %;
typedef struct Grapha{
char vertext[MAX_LENGTH];
int arc[MAX_LENGTH][MAX_LENGTH]; // 鄰接矩陣
int numVertexts, numEdges; // 頂點數與邊數
} Grapha, *P_Grapha;
// 創建頂點方法, 9個頂點,8條邊
void createVertex(P_Grapha G) {
G->numVertexts = 9;
G->vertext[0] = 'A';
G->vertext[1] = 'B';
G->vertext[2] = 'C';
G->vertext[3] = 'D';
G->vertext[4] = 'E';
G->vertext[5] = 'F';
G->vertext[6] = 'G';
G->vertext[7] = 'H';
G->vertext[8] = 'I';
}
// 8 條帶權的邊,理解成雙向
void createEdges(P_Grapha G) {
G->numEdges = 8;
int i, j;
// 初始化邊(無向)
for(i=0; i<G->numVertexts; i++) {
for(j=0; j<G->numVertexts; j++) {
if(i == j) {
G->arc[i][j] = 0;
} else {
G->arc[i][j] = INFINITY;
}
}
}
// 設置權值
G->arc[0][1] = 10;
G->arc[0][5] = 11;
G->arc[1][0] = 10;
G->arc[1][2] = 18;
G->arc[1][6] = 16;
G->arc[1][8] = 12;
G->arc[2][1] = 18;
G->arc[2][3] = 22;
G->arc[2][8] = 8;
G->arc[3][2] = 22;
G->arc[3][4] = 20;
G->arc[3][7] = 16;
G->arc[3][8] = 21;
G->arc[4][3] = 20;
G->arc[4][5] = 26;
G->arc[4][7] = 7;
G->arc[5][0] = 11;
G->arc[5][4] = 26;
G->arc[5][6] = 17;
G->arc[6][1] = 16;
G->arc[6][5] = 17;
G->arc[6][7] = 19;
G->arc[7][3] = 16;
G->arc[7][4] = 7;
G->arc[7][6] = 19;
G->arc[8][1] = 12;
G->arc[8][2] = 8;
G->arc[8][3] = 21;
}
void createMGrah(P_Grapha *G) {
(*G) = (P_Grapha)malloc(sizeof(Grapha));
createVertex(*G);
createEdges(*G);
int i, j;
// 輸出矩陣
printf("------------ 無向鄰接矩陣 ----------\n");
for(i=0; i<(*G)->numVertexts; i++) {
if(i == 0) {
printf("----%2d |",i);
} else {
printf("%2d |",i);
}
}
printf("\n");
for(i=0; i<(*G)->numVertexts; i++) {
if(i == 0) {
printf("----%2c |",(*G)->vertext[i]);
} else {
printf("%2c |",(*G)->vertext[i]);
}
}
printf("\n");
// 實際矩陣
for(i=0; i<(*G)->numVertexts; i++) {
for(j=0; j<(*G)->numVertexts; j++) {
if(j == 0) {
if((*G)->arc[i][j] == INFINITY) {
printf("%2d-%c|%2c|",i,(*G)->vertext[i], '%');
} else {
printf("%2d-%c|%2d|",i,(*G)->vertext[i], (*G)->arc[i][j]);
}
} else {
if((*G)->arc[i][j] == INFINITY) {
printf("%2c |",'%');
} else {
printf("%2d |",(*G)->arc[i][j]);
}
}
}
printf("\n"); // 換行
}
}
// 最小生成樹
// 例如adjvex[3] = 5 lowcost[3] = 8即表示序號為5的頂點(即第6個頂點)到序號為3(兩個數組的下標都為3 即第4個頂點)的頂點的邊的權值為8
void miniSpanTree_Prim(Grapha G) {
printf("=============== 最小生成樹 ============\n"); // 換行
int min, i, j, k;
int adjvex[MAX_LENGTH]; // 保存相關頂點下標
int lowcost[MAX_LENGTH]; // 保存相關頂點間邊的權值
lowcost[0] = 0; // V0作為最小生成樹的根開始遍歷,權值為0,即V0加入生成樹
adjvex[0] = 0; // 初始化第一個頂點下標為0
// 初始化操作
for(i = 1; i<G.numVertexts; i++) {
lowcost[i] = G.arc[0][i]; // 將鄰接矩陣第0行所有權值先加入數組
adjvex[i] = 0; // 將V0頂點與之有邊的權值存入數組 并初始化都為V0的下標;
}
// 真正構建最小生成樹的過程
for(i=1; i<G.numVertexts; i++) {
min = INFINITY;
j = 1;
k = 0;
// 遍歷全部頂點,找到最小的權值 (第一次循環時,找出第0行最小的權下標)
while(j<G.numVertexts){
// 找出 lowcost數組已存儲最小權值
if(lowcost[j] != 0 && lowcost[j] < min) {
min = lowcost[j];
k = j; // 將發現的最小權值的下標存入k,以待使用。
}
j++;
}
// 打印當前頂點邊中權值最小的邊
printf("(%d,%d)", adjvex[k], k); // 輸出當前頂點邊中權值最小的邊,adjvex[k] 為上一個頂點
lowcost[k] = 0; // 將當前頂點的權值設置為0,表示此頂點已經完成任務
if(i == G.numVertexts - 1) {
lowcost[k] = 0;
}
// 鄰接矩陣k行逐個遍歷全部頂點,找最小權值
for( j=1; j < G.numVertexts; j++ ) {
if( lowcost[j]!=0 && G.arc[k][j] < lowcost[j] ) {
lowcost[j] = G.arc[k][j];
adjvex[j] = k; // 記住相關的頂點
}
}
}
}
int main(int argc, const char * argv[]) {
// 創建圖
P_Grapha G;
createMGrah(&G);
miniSpanTree_Prim(*G);
return 0;
}