一步一步学数据结构之n--n(kruskal算法)

上代码:如果有疑问的话,欢迎随时留言!

#include <stdio.h>


//闹了好长时间才闹好,如果有不懂的地方可以留言
//里面判断环的地方用到并查集

//并查集资料:http://dongxicheng.org/structure/union-find-set/
#define ENUM 15//边的数量 
#define VNUM 9//顶点的数量 
#define MV 0

typedef struct _tag_Edge //存储边的信息
{
    int begin;
    int end;
    int weight;//权值 
}Edge;

int father[VNUM]; //存储 
int son[VNUM];
int Matvix[VNUM][VNUM]=
{//图 
    {0, 10, MV, MV, MV, 11, MV, MV, MV},
    {10, 0, 18, MV, MV, MV, 16, MV, 12},
    {MV, 18, 0, 22, MV, MV, MV, MV, 8},
    {MV, MV, 22, 0, 20, MV, 24, 16, 21},
    {MV, MV, MV, 20, 0, 26, MV, 7, MV},
    {11, MV, MV, MV, 26, 0, 17, MV, MV},
    {MV, 16, MV, 24, MV, 17, 0, 19, MV},
    {MV, MV, MV, 16, 7, MV, 19, 0, MV},
    {MV, 12, 8, 21, MV, MV, MV, MV, 0},
};

void swap(Edge array[], int i, int j)
{
    Edge temp = array[i];    
    array[i] = array[j];   
    array[j] = temp;
}

void SelectionSort(Edge array[], int len) // O(n*n)
{
    int i = 0;
    int j = 0;
    int k = -1;
    
    for(i=0; i<len; i++)
    {
        k = i;       
        for(j=i; j<len; j++)
        {
            if( array[j].weight < array[k].weight )
            {
                k = j;
            }
        }        
        swap(array, i, k);
    }
}

int unionsearch(int x) //查找根结点+路径压缩
{
    if(x != father[x])
    {//通过递归找到根结点,注意边最终的end为根结点 
        father[x] =    unionsearch(father[x]);
    }
    //father[x]为x的父结点 
    return father[x];
}

int join(int x, int y) //合并
{
    int root1, root2;
    root1 = unionsearch(x);
    root2 = unionsearch(y);
    if(root1 == root2) //为环
        return 0;
    else 
    {   //root2为root1的父结点 
        father[root1] = root2;
        son[root2] += son[root1];
    }

    return 1;
}

int main()
{
        int i, j;//要使用的循环变量 
        int total = 0;//最后选出边的数量 
        int sum = 0;//最后总权值 
        int flag = 0;
        int eNUM = ENUM-1;
        
        Edge array[ENUM];//总共的边
         
        for(i=0; i<VNUM; ++i) //初始化
        {
            father[i] = i;
            son[i] = 1;
        }
              
        for(i=0; i<VNUM; i++)
        {
            for(j=0; j<VNUM; j++)
            {
                if((i<j) && (0 < Matvix[i][j]))
                {//给边的结构体初始化 
                    array[eNUM].begin = i;
                    array[eNUM].end   = j;
                    array[eNUM--].weight= Matvix[i][j];
                }
            }
        } 
        
        //排序 ,对边按照权值排序,从小到大 
        SelectionSort(array, ENUM);
        
        for(i=0; i<ENUM; i++)
        {    
            if(join(array[i].begin, array[i].end))
            {//判断是否成环
                total++; //边数加1
                sum += array[i].weight; //记录权值之和
                printf("%d -> %d  weight:%d\n", array[i].begin, array[i].end, array[i].weight);
            }
            if(total == VNUM-1) //最小生成树条件:边数=顶点数-1
            {
                flag = 1;
                break;
            }
        }
        if(flag)
            printf("%d\n", sum);
        else
            printf("error.\n");

        return 0;
}


 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值