普里姆演算法思路
演算法思想:可取圖中任意一個頂點V作為生成樹的根,之後若要往生成樹上新增頂點W,則在頂點V和W之間必定存在一條邊。並且該邊的權值在所有連通頂點V和W之間的邊中取值最小。
一般情況下,假設n個頂點分成兩個集合:U(包含已落在生成樹上的結點)和V-U(尚未落在生成樹上的頂點),則在所有連通U中頂點和V-U中頂點的邊中選取權值最小的邊
C語言程式碼如下:
//最小生成樹 普里姆演算法 採用鄰接矩陣儲存 void MiniSpanTree(MGraph *G) { int min, i, j, k; int adjvex[MaxVex]; //儲存相關頂點下標 int lowcost[MaxVex]; //儲存相關頂點間邊的權值 lowcost[0] = 0; //初始化第一個權值為0,即V0加入生成樹 adjvex[0] = 0; //初始化第一個頂點下標為0 for (i=1; i<G->numVertexes; ++i) { lowcost[i] = G->arc[0][i]; adjvex[i] = 0; //將v0頂點與之有邊的權值存入陣列 並初始化都為v0的下標 } for (i=1; i<G->numVertexes; ++i) { min = INFINITY; j = 1; k = 0; while (j<G->numVertexes) { //如果兩個頂點之間存在邊並且權值小於min if (lowcost[j]!=0 && lowcost[j]<min) { min = lowcost[j]; k = j; } ++j; } printf("(%d, %d)", adjvex[k], k); //輸出當前頂點邊中權值最小的邊 lowcost[k] = 0; //將當前頂點的權值設為0,表示此頂點已經完成任務 for (j=1; j<G->numVertexes; ++j) { if (lowcost[j]!=0 && G->arc[k][j]<lowcost[j]) { lowcost[j] = G->arc[k][j]; adjvex[j] = k; } } } }
首先是變數的定義,min在每次迴圈中都存放著lowcost陣列中最小的權值。
adjvex與lowcost陣列中的下標分別對應了該圖中的頂點,如下標為1對應了第2個頂點(頂點的序號從0開始)。
例如adjvex[3] = 5 lowcost[3] = 8即表示序號為5的頂點(即第6個頂點)到序號為3(兩個陣列的下標都為3 即第4個頂點)的頂點的邊的權值為8
接著初始化lowcost[0]與adjvex[0]為0,即表示第0號結點加入生成樹,lowcost[i] = 0表示第i個結點加入到生成樹中
然後 一個迴圈將adjvex陣列的值全都置為0並且將v0到其他頂點的權值都存入lowcost陣列中。
一個包含所有頂點的大迴圈,所有的工作都在該迴圈體內完成
①假設現在是第一次迴圈 即第一個頂點加入生成樹,第23行~33行,求得所有與該結點相鄰的頂點的邊上的最小的權值,並將該權值存放min中,而與其相鄰的那個頂點的序號存入k中。即找到一個頂點k並且v0到k的權值是所有v0的鄰接點中最小的。
②/輸出當前頂點邊中權值最小的邊 即輸出adjvex[k], k 因為是第一次迴圈 所有adjvex[k] = 0, k即剛才所得到的那個權值最小的相鄰的頂點的序號。即表示adjvex[k]號頂點到k號頂點
③lowcost[k] = 0; 表示 第k號頂點已經加入到生成樹種
④第36行~43行 if (lowcost[j]!=0 && G->arc[k][j]<lowcost[j]) 如果頂點j沒有加入生成樹 並且k頂點到j頂點的權值要小於對應的lowcost陣列中第j個元素的權值,那麼就講該權值存入Lowcost陣列並將j存入adjvex中。也就是說,當我加入了一個k頂點到生成樹中以後,那麼生成樹中必然會多一些k頂點與其鄰接點的邊出來,那麼我要看下這些邊上的權值是否有小於lowcost陣列中對應位置上的值(初始狀態lowcost陣列中的值都是v0到各個頂點的邊的權值),如果小於那麼就說明頂點k到頂點j的邊的權值要比V0到j的邊的權值小。我們當然要儲存這個結果,那麼就修改adjvex[j] = k lowcost[j] = G->arc[k][j]; 即k頂點到j頂點的權值為 G->arc[k][j];
以後每次加入一個新的頂點都要看其與其鄰接點的邊上的權值是否要小於lowcost陣列中對應頂點的權值。如果小於就修改
然後找到Lowcost陣列中最小的權值 並將其與頂點輸出