Kruskal演算法 - C語言詳解

來源:互聯網
上載者:User

標籤:lock   kruskal   algorithm   weight   height   print   oid   null   star   

最小產生樹

在含有n個頂點的連通圖中選擇n-1條邊,構成一棵極小連通子圖,並使該連通子圖中n-1條邊上權值之和達到最小,則稱其為連通網的最小產生樹。 

例如,對於如G4所示的連通網可以有多棵權值總和不相同的產生樹。

克魯斯卡爾演算法介紹

克魯斯卡爾(Kruskal)演算法,是用來求加權連通圖的最小產生樹的演算法。

基本思想:按照權值從小到大的順序選擇n-1條邊,並保證這n-1條邊不構成迴路。 
具體做法:首先構造一個只含n個頂點的森林,然後依權值從小到大從連通網中選擇邊加入到森林中,並使森林中不產生迴路,直至森林變成一棵樹為止。

克魯斯卡爾演算法圖解

以G4為例,來對克魯斯卡爾進行示範(假設,用數組R儲存最小產生樹結果)。

第1步:將邊<E,F>加入R中。 
    邊<E,F>的權值最小,因此將它加入到最小產生樹結果R中。 
第2步:將邊<C,D>加入R中。 
    上一步操作之後,邊<C,D>的權值最小,因此將它加入到最小產生樹結果R中。 
第3步:將邊<D,E>加入R中。 
    上一步操作之後,邊<D,E>的權值最小,因此將它加入到最小產生樹結果R中。 
第4步:將邊<B,F>加入R中。 
    上一步操作之後,邊<C,E>的權值最小,但<C,E>會和已有的邊構成迴路;因此,跳過邊<C,E>。同理,跳過邊<C,F>。將邊<B,F>加入到最小產生樹結果R中。 
第5步:將邊<E,G>加入R中。 
    上一步操作之後,邊<E,G>的權值最小,因此將它加入到最小產生樹結果R中。 
第6步:將邊<A,B>加入R中。 
    上一步操作之後,邊<F,G>的權值最小,但<F,G>會和已有的邊構成迴路;因此,跳過邊<F,G>。同理,跳過邊<B,C>。將邊<A,B>加入到最小產生樹結果R中。

此時,最小產生樹構造完成!它包括的邊依次是:<E,F> <C,D> <D,E> <B,F> <E,G> <A,B>

克魯斯卡爾演算法分析

根據前面介紹的克魯斯卡爾演算法的基本思想和做法,我們能夠瞭解到,克魯斯卡爾演算法重點需要解決的以下兩個問題: 
問題一 對圖的所有邊按照權值大小進行排序。 
問題二 將邊添加到最小產生樹中時,怎麼樣判斷是否形成了迴路。

問題一很好解決,採用排序演算法進行排序即可。

問題二,處理方式是:記錄頂點在"最小產生樹"中的終點,頂點的終點是"在最小產生樹中與它連通的最大頂點"(關於這一點,後面會通過圖片給出說明)。然後每次需要將一條邊添加到最小生存樹時,判斷該邊的兩個頂點的終點是否重合,重合的話則會構成迴路。 以來進行說明:

在將<E,F> <C,D> <D,E>加入到最小產生樹R中之後,這幾條邊的頂點就都有了終點:

(01) C的終點是F。 
(02) D的終點是F。 
(03) E的終點是F。 
(04) F的終點是F。

關於終點,就是將所有頂點按照從小到大的順序排列好之後;某個頂點的終點就是"與它連通的最大頂點"。 因此,接下來,雖然<C,E>是權值最小的邊。但是C和E的重點都是F,即它們的終點相同,因此,將<C,E>加入最小產生樹的話,會形成迴路。這就是判斷迴路的方式。

克魯斯卡爾演算法的代碼說明

有了前面的演算法分析之後,下面我們來查看具體代碼。這裡選取"鄰接矩陣"進行說明,對於"鄰接表"實現的圖在後面的源碼中會給出相應的源碼。

1. 基本定義

// 鄰接矩陣typedef struct _graph{    char vexs[MAX];       // 頂點集合    int vexnum;           // 頂點數    int edgnum;           // 邊數    int matrix[MAX][MAX]; // 鄰接矩陣}Graph, *PGraph;// 邊的結構體typedef struct _EdgeData{    char start; // 邊的起點    char end;   // 邊的終點    int weight; // 邊的權重}EData;

Graph是鄰接矩陣對應的結構體。 
vexs用於儲存頂點,vexnum是頂點數,edgnum是邊數;matrix則是用於儲存矩陣資訊的二維數組。例如,matrix[i][j]=1,則表示"頂點i(即vexs[i])"和"頂點j(即vexs[j])"是鄰接點;matrix[i][j]=0,則表示它們不是鄰接點。 
EData是鄰接矩陣邊對應的結構體。

2. 克魯斯卡爾演算法

#include<stdio.h>#include<stdlib.h>#include<malloc.h>#include<string.h>#define MAX 100#define INF -1typedef struct Graph{    char vexs[MAX];    int vexnum;    int edgnum;    int matrix[MAX][MAX];}Graph,*PGraph;typedef struct EdgeData{    char start;    char end;    int weight;}EData;static int get_position(Graph g,char ch){    int i;    for(i=0;i<g.vexnum;i++)        if(g.vexs[i]==ch)            return i;    return -1;}Graph* create_graph(){    char vexs[]= {‘A‘,‘B‘,‘C‘,‘D‘,‘E‘,‘F‘,‘G‘};    int matrix[][7]= {        {0,12,INF,INF,INF,16,14},        {12,0,10,INF,INF,7,INF},        {INF,10,0,3,5,6,INF},        {INF,INF,3,0,4,INF,INF},        {INF,INF,5,4,0,INF,8},        {16,7,6,INF,2,0,9},        {14,INF,INF,INF,8,9,0}};    int vlen=sizeof(vexs)/sizeof(vexs[0]);    int i,j;    Graph *pG;    if((pG=(Graph*)malloc(sizeof(Graph)))==NULL)        return NULL;    memset(pG,0,sizeof(pG));    pG->vexnum=vlen;    for(i=0;i<pG->vexnum;i++)        pG->vexs[i]=vexs[i];    for(i=0;i<pG->vexnum;i++)        for(j=0;j<pG->vexnum;j++)            pG->matrix[i][j]=matrix[i][j];    for(i=0;i<pG->vexnum;i++)    {        for(j=0;j<pG->vexnum;j++)        {            if(i!=j&&pG->matrix[i][j]!=INF)                pG->edgnum++;        }    }    pG->edgnum/=2;    return pG;}void print_graph(Graph G){    int i,j;    printf("Matrix Graph: \n");    for(i=0;i<G.vexnum;i++)    {        for(j=0;j<G.vexnum;j++)            printf("%10d ",G.matrix[i][j]);        printf("\n");    }}EData* get_edges(Graph G){    EData *edges;    edges=(EData*)malloc(G.edgnum*sizeof(EData));    int i,j;    int index=0;    for(i=0;i<G.vexnum;i++)    {        for(j=i+1;j<G.vexnum;j++)        {            if(G.matrix[i][j]!=INF)            {                edges[index].start=G.vexs[i];                edges[index].end=G.vexs[j];                edges[index].weight=G.matrix[i][j];                index++;            }        }    }    return edges;}void sort_edges(EData *edges,int elen){    int i,j;    for(i=0;i<elen;i++)    {        for(j=i+1;j<elen;j++)        {            if(edges[i].weight>edges[j].weight)            {                EData tmp=edges[i];                edges[i]=edges[j];                edges[j]=tmp;            }        }    }}int get_end(int vends[],int i){    while(vends[i]!=0)        i=vends[i];    return i;}void kruskal(Graph G){    int i,m,n,p1,p2;    int length;    int index=0;    int vends[MAX]={0};    EData rets[MAX];    EData *edges;    edges=get_edges(G);    sort_edges(edges,G.edgnum);    for(i=0;i<G.edgnum;i++)        printf("%d ",edges[i].weight);    printf("\n");    for(i=0;i<G.edgnum;i++)    {        p1=get_position(G,edges[i].start);        p2=get_position(G,edges[i].end);        m=get_end(vends,p1);        n=get_end(vends,p2);        printf("m= %d,n= %d",m,n);        if(m!=n)        {            vends[m]=n;            rets[index++]=edges[i];        }    }    free(edges);    length=0;    for(i=0;i<index;i++)        length+=rets[i].weight;    printf("Kruskal = %d\n",length);    for(i=0;i<index;i++)        printf("( %c , %c ) ",rets[i].start,rets[i].end);    printf("\n");}int main(){    Graph *pG;    pG=create_graph();    print_graph(*pG);    kruskal(*pG);}

運行結果:

 

Kruskal演算法 - C語言詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.