22. 并查集

一、什么是并查集

  并查集(Disjoint Set)是一种数据结构,用于管理一组不相交的集合,并支持两种主要操作:

  • 查找(Find) :确定一个元素属于哪个集合,或者判断两个元素是否属于同一个集合。
  • 合并(Union) :将两个不同的集合合并为一个集合。

  并查集的核心思想是通过树形结构来表示集合,其中每个集合由一个根节点代表,根节点通常是集合中的一员,而且是自己的父节点。

并查集

二、创建并查集

DisjointSet * CreateDisjointSet(void)
{
    DisjointSet * S= (DisjointSet *)calloc(MAX_SIZE, sizeof(DisjointSet));

    for (int i = 0; i < MAX_SIZE; i++)
    {
        S[i].Data = i;
        S[i].Parent = -1;
    }

    return S;
}

二、集合的查找

/**
 * @brief 查找某个元素所在的集合
 * 
 * @param S 并查集
 * @param X 要查找的元素
 * @return int 如果找到返回集合的根结点的下标,否则返回-1
 */
int Find(DisjointSet S[], ElementType X)
{
    int i = 0, j = 0;

    for ( i = 0; i < MAX_SIZE && S[i].Data != X; i++);
    if (i >= MAX_SIZE)
    {
        return -1;
    }

    j = i;                                                                      // X的下标
  
    for (; S[i].Parent >= 0; i = S[i].Parent);                                  // 找到X所属的集合的根结点的下标i

    // 路径压缩
    while (j != i)
    {
        int t = S[j].Parent;
        S[j].Parent = i;                                                        // 直接将j的父结点指向根结点
        j = t;
    }
  
    return i;
}

三、集合的并运算

  分别找到 X1 和 X2 两个元素所在集合树的根结点。如果它们不同根,则将其中一个根结点的父结点指针设置为另一个根结点的数组下标。

/**
 * @brief 合并两个集合
 * 
 * @param S 并查集
 * @param X 集合1中的元素
 * @param Y 集合2中的元素
 */
void Union(DisjointSet S[], ElementType X, ElementType Y)
{
    int Root1 = 0, Root2 = 0;

    Root1 = Find(S, X);
    Root2 = Find(S, Y);

    if (Root1 != Root2)
    {
        if (S[Root1].Parent > S[Root2].Parent)                                  // Root2的集合结点数多
        {
            S[Root2].Parent += S[Root1].Parent;                                 // 累计结点总数
            S[Root1].Parent = Root2;                                            // 小树合并到大树
        }
        else
        {
            S[Root1].Parent += S[Root2].Parent;
            S[Root2].Parent = Root1;
        }
    }
}
posted @ 2023-07-27 21:43  星光樱梦  阅读(49)  评论(0编辑  收藏  举报