演算法思想:可取圖中任意一個頂點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;//初始化第一個頂點下標為0for (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){//如果兩個頂點之間存在邊並且權值小於minif (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數組中最小的權值 並將其與頂點輸出