不相交集 / 并查集(C语言实现)

两个等价类集合Si和Sj如果满足:Si和Sj的交集为空集,则称Si和Sj构成一个不相交集。

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。 集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

下面我们用数组存储森林,从而实现并查集。

代码如下:

DisjSet.h

#ifndef DisjSet_DisjSet_h
#define DisjSet_DisjSet_h

const int NumSets = 10;

/*
 * Disjoint Set 不相交集 / 并查集
 * 主要操作为:查找和合并
 */
typedef int DisjSet[NumSets + 1]; // 为了下标对齐,这里设定数组大小为NumSets + 1,第0个元素起占位作用
typedef int SetType; // 父节点保存的元素的类型
typedef int ElementType;

// 初始化
void initialize(DisjSet set);

// (按树的大小)合并两个不相交集,root1和root2分别表示两棵要合并的树的根
void setUnion(DisjSet set, SetType root1, SetType root2);

// 查找x属于set中的哪个不相交集
SetType find(ElementType x, DisjSet set);

#endif

DisjSet.c

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

void
initialize(DisjSet set)
{
    /*
     * 初始化时,每个根节点中保存的值就是该树的大小的负值,也就是-1
     * 在这里,树的大小的意思是树中有多少个节点
     * 如果节点中保存的值为正数,那么该值表示父节点在数组中的下标
     *
     * 注意:
     * 数组的下标就是节点中保存的元素
     * 数组中的元素表示父节点中保存的元素或树的大小的负值
     */
    for (int i = NumSets; i > 0; i--)
        set[i] = -1;
    
    // do nothing with set[0]
}

/*
 * 按树的大小求并:较小的树成为较大的树的子树
 */
void
setUnion(DisjSet set, SetType root1, SetType root2)
{
    if (set[root1] >= 0 || set[root2] >= 0)
        printf("Fail to union: Root1 and Root2 is not a root of tree");
    
    if (set[root1] == set[root2]) // 同一棵树
        return;
    else
    {
        if (set[root1] > set[root2]) // -set[root1] < -set[root2]
            set[root1] = root2;
        else // -set[root1] > -set[root2]
            set[root2] = root1;
    }
}

SetType
find(ElementType x, DisjSet set)
{
    if (x > NumSets)
    {
        printf("x is not in DisjSet");
        return 0;
    }
    
    if (set[x] == 0) // 空树或该节点指向占位的第0个数组元素,因此出错
    {
        printf("Error: set[x] can not be 0");
        return 0;
    }
    
    /*
     * 在查找到某个元素后,执行路径压缩算法
     * 注意:路径压缩算法和按大小合并算法兼容,和按树高度合并算法不兼容
     */
    if (set[x] < 0)
        return x;
    else
        return set[x] = find(set[x], set); // 沿上查找根节点,并设为x的父节点
}

主要参考了Mark Allen Weiss的《数据结构与算法分析 —— C语言描述》。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值