寻找最小生成树——克鲁斯卡尔(Kruskal)算法

(写于December 13th, 2012

Kruskal算法的基本思想:

设有一个有n个顶点的连通网N={V,E},将N中的边按照权值从小到大的顺序排列。

①将n个顶点看成n个集合;

②按权值由小到大的顺序选择边,所选边应满足两个顶点不在同一个顶点集合内,将该边放到生成树边的集合中,同时将该边的两个顶点所在的顶点集合合并。

③重复②直到所有的顶点都在同一个顶点集合内。

其实这个算法理解起来挺容易的,但是我在实现的过程中遇到最大的困难就是对于点集的划分和查找,最后就想到了要用到并查集,也就是说可以先把每个顶点都看成一个点集,然后每次添加边可以把边看做是等价关系中的一对序偶关系,这样,每次添加边的过程相当于对一个集合进行等价类的划分。

这是我用c实现的代码:

主函数:

#include<stdio.h>                                             
#include<string.h>                                             
#include<stdlib.h>                                             
#include <limits.h>                                             
#include"adjmatrix.h"                                             
#include"vexnum.h"                                             
                                                                                             
int main()                                             
{                                             
    AdjMatrix G;                                             
    vex ver[MAX_VERTEX_NUM];                                             
    ParentTree min;                                             
    int i;                                             
    CreateDN(&G);//创建网                                             
    printf("邻接矩阵:\n");                                             
    printadj(G);//打印矩阵                                             
    order(&G,ver);//根据权值大小排序                                             
    printf("网中所有边的按照权值大小排序:\n");                                             
    for(i=0;i<G.arcnum;i++)                                             
    {                                             
        printf("(%c,%c):%d\n",ver[i].start,ver[i].end,ver[i].weight);                                             
    }                                             
    select(ver,&min,G);                                             
    return 0;                                             
}

adjmatrix.h文件:
#define MAX_VERTEX_NUM 20                                         
#define INFINITY INT_MAX                                         
typedef struct ArcNode                                         
{                                         
    int adj;                                         
}ArcNode;                                         
typedef struct
{                                         
    char vertex[MAX_VERTEX_NUM];                                         
    ArcNode arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];                                         
    int vexnum,arcnum;//图的顶点数和弧数                                         
}AdjMatrix;                                         
int LocateVertex(AdjMatrix *G,char v)                                         
{                                         
    int j=-1,k;                                         
    for(k=0;k<G->vexnum;k++)                                         
        if(G->vertex[k]==v)                                         
        {                                         
            j=k;                                         
            break;                                         
        }                                         
    return j;                                         
}                                         
int CreateDN(AdjMatrix *G)                                         
{                                         
    int i,j,k,weight;                                         
    char v1,v2;                                         
    printf("请输入图的顶点数和弧数:\n");                                         
    scanf("%d,%d",&G->vexnum,&G->arcnum);                                         
    getchar();                                         
    for(i=0;i<G->vexnum;i++)                                         
    {                                         
        for(j=0;j<G->vexnum;j++)                                         
        {                                         
            G->arcs[i][j].adj=INFINITY;                                         
        }                                         
    }                                         
    printf("输入图的定点:\n");                                         
    for(i=0;i<G->vexnum;i++)                                         
    {                                         
        scanf("%c",&G->vertex[i]);                                         
        getchar();                                         
    }                                         
    printf("依次输入弧的两个顶点及权值:\n");                                         
    for(k=0;k<G->arcnum;k++)                                         
    {                                         
        scanf("%c,%c,%d",&v1,&v2,&weight);                                         
        getchar();                                         
        i=LocateVertex(G,v1);                                         
        j=LocateVertex(G,v2);                                         
        if(i!=-1&&j!=-1)                                         
        {                                         
        G->arcs[i][j].adj=weight;                                         
        G->arcs[j][i].adj=weight;                                         
        }                                         
        else
        {                                         
            printf("顶点找不到!\n");                                         
            exit(1);                                         
        }                                         
    }                                         
    return 0;                                         
}                                         
int printadj(AdjMatrix G)//打印邻接矩阵                                         
{                                         
    int i,j;                                         
    for(i=0;i<G.vexnum;i++)\                                         
    {                                         
        for(j=0;j<G.vexnum;j++)                                         
        {                                         
            if(G.arcs[i][j].adj==INFINITY)                                         
                printf("~ ");                                         
            else
                printf("%d ",G.arcs[i][j].adj);                                         
        }                                         
        printf("\n");                                         
    }                                         
    return 0;                                         
}

vexnum.h文件:
typedef struct
{                                       
    char start;                                       
    char end;                                       
    int weight;//权值                                       
}vex;//存放每条边的信息                                       
                                                                                 
typedef struct TNode                                       
{                                       
    char data;                                       
    int parent;//标志每个结点是否属于同一个点集                                       
}TNode;                                       
typedef struct
{                                       
    TNode tree[MAX_VERTEX_NUM];                                       
    int nodenum;//结点数                                       
}ParentTree;//点集(利用并查集)                                       
                                                                                 
//根据权值大小为边集排序                                       
int order(AdjMatrix *G,vex ver[MAX_VERTEX_NUM])                                       
{                                       
    int i,j,k=0,change=1,cost;                                       
    char v1,v2;                                       
    //初始化                                       
    for(i=0;i<G->vexnum;i++)                                       
    {                                       
        for(j=i;j<G->vexnum;j++)                                       
        {                                       
            if(G->arcs[i][j].adj!=INFINITY)                                       
            {                                       
                ver[k].start=G->vertex[i];                                       
                ver[k].end=G->vertex[j];                                       
                ver[k].weight=G->arcs[i][j].adj;                                       
                k++;                                       
            }                                       
        }                                       
    }                                       
    for(i=0;i<G->arcnum-1&&change==1;i++)                                       
    {                                       
        change=0;                                       
        for(j=0;j<G->arcnum-i-1;j++)                                       
        {                                       
            if(ver[j].weight>ver[j+1].weight)                                       
            {                                       
                v1=ver[j].start;                                       
                v2=ver[j].end;                                       
                cost=ver[j].weight;                                       
                                                                                                 
                ver[j].start=ver[j+1].start;                                       
                ver[j].end=ver[j+1].end;                                       
                ver[j].weight=ver[j+1].weight;                                       
                                                                                                 
                ver[j+1].start=v1;                                       
                ver[j+1].end=v2;                                       
                ver[j+1].weight=cost;                                       
                                                                                                 
                change=1;                                       
            }                                       
        }                                       
    }                                       
    return 0;                                       
}                                       
                                                                                 
//查找元素的下标                                       
int Locate(ParentTree min,char v)                                       
{                                       
    int i;                                       
    for(i=0;i<min.nodenum;i++)                                       
    {                                       
        if(min.tree[i].data==v)                                       
            return i;                                       
    }                                       
    return -1;                                       
}                                       
                                                                                 
//从新划分等价类(parent相等为一个等价类集合)                                       
void change(ParentTree *min,int b,int a)                                       
{                                       
    int i,n=min->tree[b].parent;                                       
    for(i=0;i<min->nodenum;i++)                                       
    {                                       
        if(min->tree[i].parent==n)                                       
        {                                       
            min->tree[i].parent=min->tree[a].parent;                                       
        }                                       
    }                                       
}                                       
                                                                                 
//选择最小的权值并且顶点不在同一个集合内放入生成树边的集合中                                       
int select(vex ver[MAX_VERTEX_NUM],ParentTree *min,AdjMatrix G)                                       
{                                       
    int i,a,b;                                       
    min->nodenum=G.vexnum;                                       
    for(i=0;i<G.vexnum;i++)                                       
    {                                       
        min->tree[i].parent=i;//初始让每个结点都个子为一个集合                                       
        min->tree[i].data=G.vertex[i];                                       
    }//初始化并查集                                       
    printf("最小生成树:\n");                                       
    for(i=0;i<G.arcnum;i++)                                       
    {                                       
        a=Locate(*min,ver[i].start);                                       
        b=Locate(*min,ver[i].end);                                       
        if(min->tree[a].parent!=min->tree[b].parent)                                       
        {                                       
            printf("(%c,%c) ",ver[i].start,ver[i].end);//若不属于同一个点集则输出最小生成树                                       
            change(min,b,a);//将新入的边集划分到点集中                                       
        }                                       
    }                                       
    printf("\n");                                       
    return 0;                                       
}


对于下图:(自己画的,比较简陋)

程序输入:

运行结果:

学弱花了不少时间终于将它实现好啦~最大的感受就是用离散数学中的知识虽然很快就可以理解的算法思想,但是实现起来还有一定的距离。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值