構造連通網的最小代價生成樹

一、普里姆算法(Prim)

1、條件:圖爲鄰接矩陣結構(Adjacency List)

2、原理:假設 WN=(V,{E}) 是一個含有 n 個頂點的連通網,TV 是 WN 上最小生成樹中頂點的集合,TE 是最小生成樹中邊的集合。顯然,在算法執行結束時,TV=V,而 TE 是 E 的一個子集。在算法開始執行時,TE 爲空集,TV 中只有一個頂點,因此,按普里姆算法構造最小生成樹的過程爲:在所有“其一個頂點已經落在生成樹上,而另一個頂點尚未落在生成樹上”的邊中取一條權值爲最小的邊,逐條加在生成樹上,直至生成樹中含有 n-1條邊爲止

3、code

void MiniSpanTree_Prim(MGraph G)
{
    int min,i,j,k;
    int adjvex[MAXVEX];    /*保存相關頂點下標*/
    int lowcost[MAXVEX];    /*保存相關頂點的權值,存放的是最小生成樹到剩下頂點的最小權值*/
    int lowcost[0]=0;    /*初始化第一個權值爲0,即v0加入生成樹,假設v0下標爲0*/
    for(i=1;i<G.numVertexes;i++)
    {
        lowcost[i]=G.arc[0][i];    /*arc爲鄰接矩陣的弧數組*/
                                   /*將第一個頂點v0與之有邊的權值存入數組*/
        adjvex[i]=0;    /*初始化都爲v0的下標*/
    }
    for(i=1;i<G.numVertexes;i++)
    {
        min=INFINITY;    /*初始化最小權限值爲∞,便於比較*/
        j=1;i=0;
        while(j<G.numVertexes)
        {
            if(lowcost[j]!=0&&lowcost[j]<min)    /*lowcost[j]==0表示已將該頂點歸入生成樹了,不必比較了*/
            {
                min=lowcost[j];    /*當前權值爲最小值*/
                k=j;     /*記錄該值*/
            }
            j++;
        }
        printf("(%d,%d)",adjvex[k],k);    /*即adjvex[k]頂點與k頂點之間有同路*/
        lowcost[k]=0;    /*將當前頂點的權值設爲0,表示將該頂點歸入生成樹*/
        for(j=1;j<G.numVertexes;j++)
        {
            /*下面的循環的意思是在所有“其一個頂點已經落在生成樹上,而另一個頂點尚未落在生成樹上”的邊中取一條權值爲最小的邊*/
            if(lowcost[j]!=0 && G.arc[k][j]<lowcost[j])
            {
                /*若下標爲k頂點各個權值小於此前這些頂點未被加入生成樹權值*/
                lowcost[j]=G.arc[k][j];    /*將較小的權值存入lowcost*/
                adjvex[j]=k;    /*將小標爲k的頂點存入adjvex*/
            }
        }
    }
}

一、克魯斯卡爾算法(Kruskal)

1、條件:邊集數組結構(Edge)

2、原理:設有一個有n個頂點的連通網N={V,E},最初先構造一個只有n個頂點,沒有邊的非連通圖T={V, E},圖中每個頂點自成一個連通分量。當在E中選到一條具有最小權值的邊時,若該邊的兩個頂點落在不同的連通分量上,則將此邊加入到T中;否則將此邊捨去,重新選擇一條權值最小的邊。如此重複下去,直到所有頂點在同一個連通分量上爲止。

3、code

/*對編輯數組Edge結構的定義*/
typedef struct
{
    int begin;    /*起始頂點下標*/
    int end;    /*終止頂點下標*/
    int weight;    /*權值*/
}Edge;
/*Kruskal算法生成最小生成樹*/
void MiniSpanTree_Kruskal(MGraph G)
{
    int i,n,m;
    Edge edges[MAXEDGE];    /*定義邊集數組*/
    int parent[MAXVEX];        /*定義一數組用來判斷邊與邊是否行程環路*/
    /*此處省略將鄰接矩陣G轉化爲邊集數組edges並按權由小到大排序的代碼*/
    for(i=0;i<G.numVertexes;i++)
    {
        parent[i]=0;    /*初始化數組值爲0*/
    }
    for(i=0;i<G.numVertexes;i++)
    {
        n=Find(parent,edges[i].begin);
        m=Find(parent,edges[i].end);
        if(n!=m)    /*說明此邊沒有與現有的生成樹行程環路*/
        {
            parent[n]=m;    /*將此邊的結尾頂點放入小標爲起點的parent中*/
                            /*表示n與m在同一個集合中*/
            printf("(%d,%d) %d",edges[i].begin,edges[i].end,edges[i].weight);
        }
    }
}

int Find(int *parent,int f)    /*查找連線頂點的尾部下標*/
{
    while(parent[f]>0)
        f=parent[f];
    return f;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章