树-并查集-实现和应用

并查集

定义

并查集是一种维护集合的数据结构,并:Union,查:Find,集:Set
并查集支持下面两种操作:

  1. 合并:合并两个集合
  2. 查找:判断两个元素是否在一个集合

并查集使用一个数组实现

int father[N];

其中 father[i] 代表元素 i 的父亲节点,而父亲节点本身也是这个集合内的元素。
如果 father[i] == i 说明元素 i 是该集合的根结点,但是对于同一个结合来说只存在一个根结点,且将其作为所属集合的标识

并查集的基本操作

一个实现

初始化father数组,但我们通常还会初始化另外一个辅助的数据结构 height[N], 来记录每个结点的深度,以使得我们的并查集的效率不会太差,不会生成一个非常长高的单链。

初始化

#define N 1001

int father[N]; //记录父节点
int height[N]; //记录每个节点的高度

void Initial(int n)
{
    for (int i = 0; i <= n; i++)
    {
        father[i] = i; // 初始化,父节点是自己
        height[i] = 0; // 高度为0
    }
}

查找

由于同一个集合只存在一个根结点,所以查找操作就是对给定的结点寻找其根结点的过程。

// 递归
int Find(int x)
{
    if (x != father[x])
    {
        x = Find(father[x]);
    }
    return x;
}

// 非递归
int Find(int x)
{
    while (x != father[x])
    {
        x = father[x];
    }
    return x;
}

合并

把两个集合合并成一个,思路:

  1. 首先判断两个元素是否是同一个集合,就是看二者是否有相同的根结点
  2. 如果不是同一个集合,那么把一个集合的根结点的父亲指向另一个集合的根结点
    • 我们一般会将比较矮的集合(树)指向比较高的树
void Union(int x, int y)
{
    x = Find(x);
    y = Find(y);
    if (x != y)
    {
        if (height[x] < height[y])
        { // 矮树添加到高树上
            father[x] = y;
        }
        else if (height[x] > height[y])
        {
            father[y] = x;
        }
        else
        {
            father[y] = x;
            height[x]++;
        }
    }
}
posted @ 2020-03-23 11:25  南风sa  阅读(...)  评论(...编辑  收藏