最小生成树 Kruskai (并查集)

具体的思路这里就不细讲了,网上有好多,我是看过 算法导论之后,因为其伪代码给的过于简单,想自己实现一下,参考了一篇博客,并对其进行了简单的改进,原博客比较简单好理解,一会儿附上链接,我将其中的排序改为了,快排,并讲并查集的操作写成了独立的函数

原文链接 最小生成树的Kruskal算法

代码保留了原博客的代码 (注释比较好理解)

#include<stdio.h>
#include <stdlib.h>

#define MAXSIZE 30
#define MAXCOST 32767

typedef struct
{
    int u;//边的起始顶点
    int v;//边的起始终点
    int w;//边的权值
}Edge;

void  Bubblesort(Edge R[],int e)//冒泡排序,对数组R中的e条边按权值递增排序
{
    Edge temp;
    int i,j,swap;
    for(i=0;i<e-1;j++)//进行e-1趟排序
    {
     swap=0;
     for(j=0;j<e-i-1;j++)
         if(R[j].w>R[j+1].w)
         {
             temp=R[j];R[j]=R[j+1];R[j+1]=temp;//交换R[j]和R[j+1]
             swap=1;//置有交换标志
         }
         if(swap==0) break;//本趟比较中未出现交换则结束排序
    }
}

void Kruskal(int gm[][6],int n)//在顶点为n的连接图中构造最小的生成树,gm为连通网的邻接矩阵
{
    int i, j, u1, v1, sn1, sn2, k;
    int vest[MAXSIZE];//数组vest用于判断两顶点之间是否连通
    Edge E[MAXSIZE];//MAXSIZE为可存放边数的最大常量值
    k = 0;
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            if (i < j && gm[i][j] != MAXCOST)//MAXCOST为一个极大的常量值
            {
                E[k].u = i;
                E[k].v = j;
                E[k].w = gm[i][j];
                k++;
            }
        }
    }
    Bubblesort(E,k);//采用冒泡排序对数组E中的k条边按权值递增排序
    for(i=0;i<n;i++)//初始化辅助数组
        vest[i]=i;//给每个顶点置不同连通分量编号,即初始时有n个连通分量
    k=1;//k表示当前构造生成树的第n条边,初始值为1
    j=0;//j为数组E中元素的下标,初值为0
    while(k<n)//产生最小生成树的n-1条边
    {
        u1=E[j].u;v1=E[j].v;//取一条边的头尾顶点
        sn1=vest[u1];
        sn2=vest[v1];//分别得到这两个顶点所属的集合编号
        if(sn1!=sn2)//两顶点分属于不同集合则该边为最小生成树的一条边
        {
            printf("Edge:(%d,%d),Wight:%d\n",u1,v1,E[j].w);
            k++;//生成的边数增1
            for(i=0;i<n;i++)//两个集合统一编号
                if(vest[i]==sn2)//集合编号为sn2的第i号边其边号改为sn1
                    vest[i]=sn1;
        }
        j++;//扫描下一条边
    }
}
// optimize sort function

/**
 *
<stdlib.h>  void qsort(void * base,size_t nmemb,size_t size ,int(*compar)(const void *,const void *))

参数说明:

base,要排序的数组

nmemb,数组中元素的数目

size,每个数组元素占用的内存空间,可使用sizeof函数获得

compar,指向函数的指针也即函数指针。这个函数用来比较两个数组元素,第一个参数大于,等于,小于第二个参数时,分别显示正值,零,负值。
 */
int compare(const void * a,const void * b){

    Edge* n = (Edge*)a;
    Edge* m = (Edge*)b;
    return n->w>m->w?1:-1;

}

void quick_sort(Edge e[],int k){ // k is the number of edge
    qsort(e,k,sizeof(Edge),compare);  /// ;
}



int init_Edge(Edge e[],int n,int gm[][6]){

    int i,j,k=0;
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            if (i < j && gm[i][j] != MAXCOST)//MAXCOST为一个极大的常量值
            {
                e[k].u = i;
                e[k].v = j;
                e[k].w = gm[i][j];
                k++;
            }
        }
    }
    return k;
}

/// union find  find  father
int find(int vest[],int i){

    if(vest[i] == i){
        return i;
    }
    else{
        vest[i] = find(vest,vest[i]);
    }

    return vest[i];
}

void merge(int vest[],int i,int j){
    vest[j] = vest[i];
}


// optimize Kruskal algorithm
/// use linked list save the graphic
/// or use the (ling jie biao)
/// or use std input to init Edge
int Kruskal_two(int g[][6],int n){ //n is the number or vertex

    Edge e[MAXSIZE];
    int k = init_Edge(e,n,g); ///k is the number of edge
    int vest[MAXSIZE];
    for(int i=0;i<n;i++){ //init  union array ( bing cha ji)
        vest[i] = i;
    }
    quick_sort(e,k);

    k=1; /// present the number of mst's edge
    int u1,v1,uf,vf;
    int j=0; /// itrate e
    while(k<n){
        u1 = e[j].u;
        v1 = e[j].v;
        uf = find(vest,u1);
        vf = find(vest,v1);
        if(uf!=vf){
            printf("Edge:(%d,%d),weight:%d\n",u1,v1,e[j].w);
            k++;
            merge(vest,uf,vf);
        }
        j++;
    }

    return 0;
}






void main()
{
    int g[6][6]={{100,6,1,5,100,100},{6,100,5,100,3,100},{1,5,100,5,6,4},
    {5,100,5,100,100,2},{100,3,6,100,100,6},{100,100,4,2,6,100}};
    Kruskal_two(g,6);//生成最小生成树
    printf("*****************************\n");
    Kruskal(g,6);
}

/**
 * result
 *  Edge:(0,2),weight:1
    Edge:(3,5),weight:2
    Edge:(1,4),weight:3
    Edge:(2,5),weight:4
    Edge:(1,2),weight:5
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值