1. 程式人生 > >資料結構——最小生成樹

資料結構——最小生成樹

資料結構課上講的最小生成樹思路還要程式碼和我之前寫過的ACM版的是一樣的,這裡都是兩種演算法普里姆(Prim)演算法和克魯茲卡爾(Kruskal)演算法。

普利姆演算法

struct
{
    int  adjvex; ///存放該邊所關聯的生成樹上的另一頂點的序號
    int  lowcost;///記錄當前生成樹到剩餘頂點的最小權值
} closedge[n];

int  Minimum(int closedge[], MGraph G)///求依附於生成樹上頂點中所有邊代價最下的邊
{
    int  j,p=1, min=999;///最大權值65535?
    for
(j=0; j<G.vexnum; j++) { if (closedge[j].lowcost!=0&&closedge[j].lowcost<min) { ///不在生成樹中的頂點而且權值最小 min=closedge[j].lowcost;///更新 P=j; } }/*for*/ return p; /*返回最小代價的邊所依附的生成樹外的頂點p*/ }/* Minimum*/ void MiniSpanTree_PRIM(MGraph G, int
n,char u) { /*用Prim演算法從第u個頂點出發構造網G的最小生成樹T,並輸出T的各條邊, closedge [n] 記錄從頂點集U到V-U的代價最小的邊,n為圖中頂點數*/ int i,j,k; k=LocateVex(G,u); /*求頂點u在鄰接矩陣儲存的圖中的位置*/ for(j=0; j<G.vexnum; ++j) /* 輔助陣列初始化*/ { if(j!=k) { closedge[j].adjvex=u; closedge[j].lowcost
=G.arcs[k][j].adj; } } closedge[k].lowcost=0; /*初始,U={u}*/ printf("最小代價生成樹的各條邊為:\n"); for(i=1; i<G.vexnum; ++i) /*選擇其餘G.vexnum-1個頂點*/ { k=Minimum(closedge,G); /*求出T的下個頂點,第k個頂點*/ printf("%c-%c)\n",closedge[k].adjvex,G.vexs[k]);///列印權值最小的邊 /* 輸出生成樹的邊及權值*/ closedge[k].lowcost=0; /*第k個頂點併入U集*/ for(j=0; j<G.vexnum; ++j) { if(closedge[j].lowcost!=0&&G.arcs[k][j].adj<closedge[j].lowcost)/// {///如果新加入樹的頂點k使得權值變小 /* 新頂點併入U集後重新選擇最小邊*/ closedge[j].adjvex=G.vexs[k]);///修改這條邊鄰接的頂點,表示這條邊是從選出的頂點k指過來的 closedge[j].lowcost=G.arcs[k][j].adj;///更新更小的權值 } } } }

 

說明:

1.這個程式碼多一個adjvex陣列,主要是為了列印最小生成樹的邊服務的,它用來記錄某點通過關聯的生成樹(集合U)上的另一頂點的序號。
2.lowcost陣列記錄當前生成樹到其餘頂點的最小權值。lowcost[i]=0表示i號頂點在生成樹中了,換句話說,這個lowcost陣列既有了dist陣列的功能,又有了vist陣列的功能。

 

克魯斯卡爾演算法

 

typedef struct
{
    int a,b;///邊的兩個結點
    int weight;///邊的權值
} Edge; ///邊結構體
int Find(int *parent,int x)
{
    while(parent[x]!=0)///迴圈向上尋找下標為x頂點的根
    {
        x=parent[x];
    }
    return x;///迴圈結束時找到了根的下標
}
int parent[MAXVEX];///定義生成樹的父節點(並查集)
Edge edges[MAXVEX]; ///定義邊集陣列

void MiniSpanTree_Kruskal(MGraph G)
{
    int i,n,m;
    sort(edges);///按權值從小到大對邊排序
    for (i= 0; i <G.vexnum; i++)
    {
        parent[i]=0;///初始化各個頂點單獨形成一個集合
    }
    for (i=0;i<G.arcnum;i++)
    {
        n = Find(parent, edges[i].a);///n是這條邊第一個頂點的根節點所在的下標
        m = Find(parent, edges[i].b);///n是這條邊第二個頂點的根節點所在的下標
        if (n!=m)    ///根節點下標不同,就說不在一棵樹上,不會形成環
        {
            parent[n] = m;///合併
            printf("(%d,%d) %d ", edges[i].a, edges[i].b, edges[i].weight);
        }
    }
}

這個就和之前的寫法基本一致了,並查集加排序