數據結構——最小生成樹


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

https://www.cnblogs.com/wkfvawl/p/9140591.html

普利姆算法

struct
{
    int  adjvex; ///保存鄰接頂點下標的數組
    int  lowcost;///記錄當前生成樹到剩余頂點的最小權值
} closedge[n];
 int sum=0;///最小生成樹的權值
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;
        }
    }
    sum=sum+min;///將該邊的權值加入到最小生成樹的總權值中
    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數組,主要是為了打印最小生成樹的邊服務的,它用來保存鄰接頂點的下標。
2.lowcost數組記錄當前生成樹到其余頂點的最小權值。lowcost[i]=0表示i號頂點在生成樹中了,換句話說,這個lowcost數組既有了dist數組的功能,又有了vist數組的功能。

3.adjvex數組和lowcost數組是同步更新的。一旦有新的點加入到集合中,若找到權值最小的邊,同時更新adjvex數組和lowcost。

4.數組結構課更看重求解最小生成樹的過程,因而需要去打印組成邊,而ACM比賽更看重那個結果,也就最小生成樹的權值,這里我又加上了sum,代表最小生成樹的權值。

克魯斯卡爾算法

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);
        }
    }
}

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM