并查集/路径压缩【C语言实现】

思路:结构体数组表示

typedef struct treenode{
    int data;
    int parent;
}tree;

数组中每个元素都是一个结构体,一个分量存该节点数值int data;,另一个分量int parent;存父结点的数组下标,实现了通过孩子结点找父结点的操作。
特别的,对于根结点,不再有父结点,故分量int parent;设为-1.
在优化并入操作时,我们希望有一个分量可以记录集合大小,这样能轻松实现将小的集合并入大的集合。对于这个特殊的分量,实际上只要根结点需要,所以我们把根结点的int parent;分量的大小设为负数(表示其没有父结点),绝对值设为集合元素个数。比如一个结点的int parent;为-7,代表这个结点时根结点,并且该集合中有7个元素。

操作集:
int find(tree set[],int X,int Maxsize)查找两个元素是否在一个集合
tree combine(tree set[],int m,int n)将两个元素并入一个集合
tree Union(tree set[],int m,int n)为避免随机并入元素时出现长蛇怪等现象导致树高不可控,find函数效率下降严重,我们优化并入操作,使大的集合并入小的集合
int Find( tree *S, int X )路径压缩在这里插入图片描述
代码实现:
1.查找和并入

#include<stdio.h>
#include<malloc.h>

typedef struct treenode{
    int data;
    int parent;
}tree;
int find(tree set[],int X,int Maxsize)//Maxsize为集合中总元素的个数
{
    int i=0;
    while(i<Maxsize)
    {
        if(X==set[i].data)
         break;
      i++;
    }
    if(i == Maxsize)//由于没有找到而退出while循环
      return -1;
    else//找到了
    {
        while(set[i].parent >= 0)//当找到的结点不是根结点
        {
            i=set[i].parent;//向上移动,直到根结点
        }
        return i;
    }
}
tree combine(tree set[],int m,int n)
{
    int root1,root2;
    root1 = find(set,m,10000);//先找到两个元素对应的根结点
    root2 = find(set,n,10000);
    
    if(root1 != root2)//若根结点不一样,就随机把一个树的根结点的父亲设为另外一个树的根结点
    {
        set[root2].parent=root1;
        return *set;
    }
}

2.优化后的并入操作

tree Union(tree set[],int m,int n)
{
    int root1,root2;
    root1 = find(set,m,10000);
    root2 = find(set,n,10000);

    if(root1!=root2)//当两个集合不同时
   {
       if(set[root1].parent<set[root2].parent)//集合1比集合2大
    {
        set[root2].parent=root1;
        set[root1].parent=set[root1].parent + set[root2].parent;
        return *set;
    }
       else//集合2比集合1大
    {
        set[root1].parent=root2;
        set[root2].parent=set[root1].parent + set[root2].parent;
        return *set;
    }

   } 
}

3.路径压缩

int Find( tree *S, int X )
{ /* 默认集合元素全部初始化为-1 */
    if ( S[X].data < 0 ) /* 找到集合的根 */
        return X;
    else
        return S[X].parent = Find( S, S[X].data ); /* 路径压缩 */
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值