不相交集数据结构或并查集算法简介


不相交集信息结构,也称为并查集算法,是计算机科学中的一个重要概念,它提供了一种有效的方法来解决与分区和网络相关的 问题。它在解决涉及组件集并确定它们之间连接的问题方面尤其有价值。在本文中,我们将探讨 C++ 中不相交集信息结构的语法、算法和两种不同的实现方法。我们还将提供完全可执行的代码示例来说明这些方法。

语法

在深入研究算法之前,让我们先熟悉一下以下代码示例中使用的语法。

// Create a disjoint set
DisjointSet ds(n);

// Perform union operation
ds.unionSets(a, b);

// Find the representative of a set
ds.findSet(x);

算法

在处理多个不相交集时,使用不相交集数据结构可能很有用。每个组都由一个特定的代表来标识。开始时,每个组件都形成自己的独立集,对应于其相应的代表(也正好是自己)。在不相交集上执行的两个主要操作是 union(合并)和 find(查找)。

合并操作

  • 找到要合并的两个集合的代表。

  • 如果代表不同,则使一个代表指向另一个,从而有效地合并集合。

  • 如果代表相同,则集合已经合并,无需进一步操作。

查找操作

  • 给定一个元素,找到它所属集合的代表。

  • 沿着父指针一直找到代表。

  • 返回代表作为结果。

方法 1:基于秩的合并和路径压缩

实现不相交集数据结构的一种有效方法是使用基于秩的合并和路径压缩技术。

在这种方法中,每个集合都有一个关联的秩,初始设置为 0。

在执行两个集合之间的合并操作时,优先考虑秩较高的集合,并将秩较低的集合合并到秩较高的集合中。如果两个集合的秩相同,则需要任意选择一个集合来合并另一个集合。在任何一种情况下,一旦合并成一个新的集合,它的秩就会增加 1。此外,为了加速查找操作并降低时间复杂度,路径压缩有助于在这些操作期间使树结构扁平化。

示例

#include <iostream>
#include <vector>

class DisjointSet {
   std::vector<int> parent;
   std::vector<int> rank;
    
public:
   DisjointSet(int n) {
      parent.resize(n);
      rank.resize(n, 0);
      for (int i = 0; i < n; ++i)
         parent[i] = i;
   }
    
   int findSet(int x) {
      if (parent[x] != x)
         parent[x] = findSet(parent[x]);
      return parent[x];
   }
    
   void unionSets(int x, int y) {
      int xRoot = findSet(x);
      int yRoot = findSet(y);
        
      if (xRoot == yRoot)
         return;
        
      if (rank[xRoot] < rank[yRoot])
         parent[xRoot] = yRoot;
      else if (rank[xRoot] > rank[yRoot])
         parent[yRoot] = xRoot;
      else {
         parent[yRoot] = xRoot;
         rank[xRoot]++;
      }
   }
};

int main() {
   // Example usage of DisjointSet
   int n = 5;  // Number of elements

   DisjointSet ds(n);

   ds.unionSets(0, 1);
   ds.unionSets(2, 3);
   ds.unionSets(3, 4);

   std::cout << ds.findSet(0) << std::endl;  
   std::cout << ds.findSet(2) << std::endl;  

   return 0;
}

输出

0
2

方法 2:基于大小的合并和路径压缩

不相交集数据结构的另一种方法是使用基于大小的合并和路径压缩技术。

  • 在这种方法中,每个集合都有一个关联的大小,初始设置为 1。

  • 在合并操作期间,较小的集合将合并到较大的集合中。

  • 相应地更新结果集合的大小。

  • 路径压缩应用于查找操作,以使树结构扁平化,类似于先前的方法。

示例

#include <iostream>
#include <vector>

class DisjointSet {
   std::vector<int> parent;
   std::vector<int> size;
    
public:
   DisjointSet(int n) {
      parent.resize(n);
      size.resize(n, 1);
      for (int i = 0; i < n; ++i)
         parent[i] = i;
   }
    
   int findSet(int x) {
      if (parent[x] != x)
         parent[x] = findSet(parent[x]);
      return parent[x];
   }
    
   void unionSets(int x, int y) {
      int xRoot = findSet(x);
      int yRoot = findSet(y);
        
      if (xRoot == yRoot)
         return;
        
      if (size[xRoot] < size[yRoot]) {
         parent[xRoot] = yRoot;
         size[yRoot] += size[xRoot];
      }
      else {
         parent[yRoot] = xRoot;
         size[xRoot] += size[yRoot];
      }
   }
};

int main() {
   // Example usage of DisjointSet
   int n = 5;  // Number of elements

   DisjointSet ds(n);

   ds.unionSets(0, 1);
   ds.unionSets(2, 3);
   ds.unionSets(3, 4);

   std::cout << ds.findSet(0) << std::endl;  
   std::cout << ds.findSet(2) << std::endl;  
   return 0;
}

输出

0
2

结论

不相交集数据结构或并查集算法是解决涉及集合和连接问题的强大工具。本文深入探讨了 C++ 中不相交集数据结构的语法及其算法。为了扩展我们的理解,我们为读者提供了两种独特的方法——基于秩的合并结合路径压缩,以及基于大小的合并加路径压缩。通过理解和实现这些方法,您可以有效地解决需要跟踪不相交集的各种问题。

更新时间: 2023年7月25日

1K+ 浏览量

开启您的 职业生涯

通过完成课程获得认证

开始学习
广告