数据结构——最小生成树

数据结构课上讲的最小生成树思路还要代码和我之前写过的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("最小代价生成树的各条边为:
");
    for(i=1; i<G.vexnum; ++i) /*选择其余G.vexnum-1个顶点*/
    {
        k=Minimum(closedge,G); /*求出T的下个顶点,第k个顶点*/
        printf("%c-%c)
",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);
        }
    }
}

这个就和之前的写法基本一致了,并查集加排序

原文地址:https://www.cnblogs.com/wkfvawl/p/10012200.html