1. 程式人生 > >克魯斯卡爾最短路徑演算法詳解

克魯斯卡爾最短路徑演算法詳解

									              			


void InsertSort(Edge a[],int n)    //這裡是插入排序,就是對傳入的陣列進行從小到大的排序,方便克魯斯卡爾演算法的執行
{
    int i,j,k;
    Edge temp;
    for(i=1;i<n;i++)
    {
        temp = a[i];         //建立一個輔助變數,
        j=i-1;    //將每一次陣列的第一個值與第二個比較
        while(j>=0&&temp.w<a[j].w) //大則互換,也叫插入換位
        {
            a[j+1]=a[j];
            j--;
        }
        a[j+1]=temp;
    }  //
    /*for(i=0;i<n;i++)
            /printf("%d ",a[i].w);printf("\n");*/ //這兩//句是我用來輔助你去看它的生成結果,在實際程式中可要可不要
}

void Kruskal(MGraph g)       //克魯斯卡爾演算法最小生成樹
{
int i,j,m1,m2,sn1,sn2,k;
int vset[MAXV];       //輔助陣列 ,用於放最小生成樹節點
Edge E[MAXE];          //邊集
k=0;                  //邊數變數

//下面兩個for實際上是將圖的矩陣中的資料放入陣列中,你去看課本上的圖的矩陣,就明白了,INF是無窮大的意思, 矩陣是方矩陣,長寬各為g.n 
           for(i=0;i<g.n;i++)
        for(j=0;j<g.n;j++)
        if(g.edges[i][j]!=0&&g.edges[i][j]!=INF)
        {
            E[k].u=i;E[k].v=j;E[k].w=g.edges[i][j];
            k++;
        }


     InsertSort(E,k); //邊插入排序,就是將權值從小到大依次排列

for(i=0;i<g.n;i++)     //初始化輔助陣列,儲存最小生成樹節點的編號
vset[i]=i;                  //初始化為 0.1.2.3.4.5,作用後面就知道了
//vset[]這個陣列是用來輔助克魯斯卡爾演算法的陣列,在後面中用來判斷是否會形成迴路,因為一旦形成迴路就不滿足生成樹的概念,然後你再去看最小生成樹,就是 權值之和最小並且遍歷了節點,並且只遍歷了一次 ,此時就生成了最小生成樹

k=1;            //k表示當前構造最小生成樹的第幾條邊,初值為1
j=0;             //E中邊的下標,初值0
while(k<g.n)         //生成邊數小於n時迴圈    
{
m1=E[j].u;m2=E[j].v;     //取一條邊的頭尾頂點E[j].u和E[j].v是同步變化的
sn1=vset[m1];
sn2=vset[m2];          //分別得到兩個頂點所屬的集合編號
//sn1和sn2頁是在同時變化,注意值,最好是將while這個過程畫出來

if(sn1!=sn2)            //兩頂點屬於不同的集合,
{                                //該邊是最小生成樹的一條邊
printf("  (%d,%d):%d\n",m1,m2,E[j].w);
k++;             //生成邊數加1
for(i = 0;i<g.n;i++) //兩個集合統一編號,統一為小值這裡就是判斷是否形成迴路了,迴圈檢查,如果有相等,直接跳過

if(vset[i]==sn2)    //集合編號為sn2的改為sn1 vset[i]=sn1;
}
j++;                 //掃描下一條邊
}
}