并查集

一、并查集的概念

并查集是一种管理元素分组情况的数据结构,主要实现以下两个功能:

  • 查询元素 \(a\)\(b\) 是否在同一集合
  • 合并元素 \(a\)\(b\) 所在的集合

注:并查集只能进行合并操作,不能进行分割操作。


二、并查集的实现

一般,我们采用数组 par[]height[] 来实现并查集。

  • par[x]\(x\) 的父节点(若 \(par[x] = x\),则 \(x\) 为根节点)
  • height[x]\(x\) 所在树的深度(作用于合并树时防止树的退化)

2.1 init()

首先,要对每一个元素初始化。一开始还未对元素进行分类,所以每个元素独自为一棵树,\(par[x] = x\)。此时,每棵树的深度都为0,\(height[x] = 0\)

2.2 find()

该函数用于查询元素 \(x\) 的根节点,采用了递归的思想。注意,这里采用了路径压缩,每次查询时,把树中的节点都直接连接到根节点上。

2.3 same()

该函数用于判断两个元素是否属于同一集合,只要查询各自的根节点是否相同就行了。

2.4 unite()

该函数用于合并两个元素所在的集合,核心思想是把一棵树的根节点的父节点改为另一棵树的根节点。这里有两点要注意:第一,要把深度小的树合并到深度大的树中,这样可以防止退化;第二,若合并两棵深度一样的树,合并后,树的深度要加1。


三、代码

// 并查集
#define MAX 10

int par[MAX];           // 该节点的父节点
int height[MAX];        // 树的深度

// 初始化
void init(void)
{
    for (int i = 0; i < MAX; i++)
    {
        par[i] = i;                  // 每个元素独自构成一棵树
        height[i] = 0;               // 只有根节点,深度为0
    }
}

// 查询元素 x 的根节点
int find(int x)
{
    if (par[x] == x)                    // 父节点为自身,表示为根节点
        return x;
    else
        return par[x] = find(par[x]);   // 压缩路径
}

// 查询元素 x 和 y 是否在一棵树中
bool same(int x, int y)
{
    return find(x) == find(y);
}

// 合并元素 x 和 y 所在的树
void unite(int x, int y)
{
    x = find(x), y = find(y);
    if (x == y)                       // 已在同一棵树中
        return;

    if (height[x] < height[y])        // 深度小的树合并到深度大的树中,防止退化
        par[x] = y;
    else
    {
        par[y] = x;
        if (height[x] == height[y])   // 若深度相同,则合并后深度加1
            height[x]++;
    }
}

posted @ 2024-02-06 14:16  ltign  阅读(4)  评论(0编辑  收藏  举报