C++实现并查集

1、并查集概念

当我们需要判断一个集合中的两个元素x,y是否同属于一个集合时,我们可以使用并查集的方法进行查询。其核心思路在于将一个数组转化成一棵树的形式:每个节点初始时都认为是一棵独立的树,当两个节点同属于一个集合时,我们可以将其中一个节点指向另一个节点用于表示两个节点同属于一个集合。因此当我们想要确定两个节点是否同属于一个子集时,我们只需要比较他们二者的根节点是否相同即可。因此并查集中的基础操作有两个:find判断两个节点是否相同;union合并两个相同的节点。

2、并查集实现

1、Find()

实现find函数时,由于我们初始化时将各个节点的父节点parent[x]定义为自己本身,因此在查询时若parent[x]等于自己说明自己就是根节点,可以直接返回;若不相等说明自己的parent[x]记录的是其父节点的值,将其传入find继续查找。

int find(int x)
{
    return parent[x] == x ? x : find(parent[x]);
}

2、Union()

当两个元素同属于一个子集时,我们需要将两个独立的树进行合并,此时我们可以将其中一棵树的根节点指向另一棵树的根节点实现合并。

void to_union(int x1, int x2) 
{
    int p1 = find(x1);
    int p2 = find(x2);
    parent[p1] = p2;
}

3、完整代码

#include 
class DisjSet
{
private:
    std::vector<int> parent;

public:
    DisjSet(int max_size) : parent(std::vector<int>(max_size))
    {
        // 初始化每一个元素的根节点都为自身
        for (int i = 0; i < max_size; ++i)
            parent[i] = i;
    }
    int find(int x)
    {
        return parent[x] == x ? x : find(parent[x]);
    }
    void to_union(int x1, int x2)
    {
        parent[find(x1)] = find(x2);
    }
    // 判断两个元素是否属于同一个集合
    bool is_same(int e1, int e2)
    {
        return find(e1) == find(e2);
    }
};

3、并查集优化

为了优化并查集的查找和合并效率,我们有两种方法进行优化:

1、按秩合并

实际上就是在合并两棵树时,将高度较小的树合并到高度较大的树上。通常情况我们令只有一个节点的树的秩为0,如果秩不相等,我们将秩小的树合并到秩大的树上,这样就能保证新树秩不大于原来的任意一棵树。如果r1与r2相等,两棵树任意合并,并令新树的秩为r1 + 1。

2、路径压缩

在执行Find的过程中,将路径上的所有节点都直接连接到根节点上。

3、优化代码

#include 
class DisjSet
{
  private:
    std::vector<int> parent;
    std::vector<int> rank; // 秩

  public:
    DisjSet(int max_size) : parent(std::vector<int>(max_size)),
                            rank(std::vector<int>(max_size, 0))
    {
        for (int i = 0; i < max_size; ++i)
            parent[i] = i;
    }
    int find(int x)
    {
        return x == parent[x] ? x : (parent[x] = find(parent[x]));
    }
    void to_union(int x1, int x2)
    {
        int f1 = find(x1);
        int f2 = find(x2);
        if (rank[f1] > rank[f2])
            parent[f2] = f1;
        else
        {
            parent[f1] = f2;
            if (rank[f1] == rank[f2])
                ++rank[f2];
        }
    }
    bool is_same(int e1, int e2)
    {
        return find(e1) == find(e2);
    }
};

你可能感兴趣的:(c++,算法,开发语言)