📜  大范围值的动态不相交集数据结构

📅  最后修改于: 2021-04-17 11:13:31             🧑  作者: Mango

先决条件:

  • 不相交集数据结构
  • Unordered_Map

不相交集数据结构用于跟踪一组元素,这些元素被划分为多个不相交(不重叠)的子集。

在本文中,我们将学习动态构建相同的数据结构。这种数据结构基本上可以解决以下情况:由于顺序10 9的大量输入而导致我们不能简单地使用数组来创建不相交集的情况。

为了说明这一点,请考虑以下问题。当顶点总数最多可以达到10 ^ 9时,我们需要在图中找到连接的组件总数。

例子:

Input : Edges : { { 1, 2 }, 
                  { 2, 3 }, 
                  { 4, 5 } }
Output : 2
Explanation: {1, 2, 3} forms a component and 
{4, 5} forms another component.

解决此问题的想法是,我们将维护两个哈希表(在C++中使用unordered_maps实现)。一个为父母而其他为学位。 Parent [V]将给出顶点V所属于的组件的父对象,而Degree将给出该组件中的顶点数。

最初,“父级”和“学位”都将为空。我们将继续按顺序向地图插入顶点。

同时查看代码和说明以更好地理解。下面是代码中用于解决上述问题的方法:

  1. getParent(V):此方法将给定顶点V的父级。在这里,我们递归地找到顶点V的父级(请参见代码),与此同时,我们将该组件中的所有顶点分配为具有相同的父级。数据结构,同一组件中的所有顶点都具有相同的父对象。)
  2. Union():当我们添加一条边并且两个顶点属于不同的组件时,我们调用Union()方法来将这两个组件连接在一起。此处,将两个组件连接在一起后形成的组件的父对象将是在联合之前具有更多顶点数量的两个组件中的组件的父对象。新组件的程度将相应更新。
  3. getTotalComponent():同一组件中的顶点将具有相同的父对象。
    我们使用unordered_set(STL)来计算组件总数。由于我们将数据结构保持为动态,因此可以有任何未添加到任何组件的顶点,因此它们是单独的不同组件。因此,组件总数将由下式给出:
    Total no of Component =  Total Vertices - Number of Vertices
                             in parent (Map)  + Number of Component 
                             formed from the Vertexes inserted 
                             in the graph.
    

下面是上述想法的实现:

C++
// Dynamic Disjoint Set Data Structure
// Union-Find
  
#include 
using namespace std;
  
int N;
int Edges[3][2];
  
// Dynamic Disjoint Set Data Structure
struct DynamicDisjointSetDS {
  
    // We will add the vertex to the edge
    // only when it is asked to i.e. maintain
    // a dynamic DS.
    unordered_map parent, degree;
  
    // Total nomber of Vertex in the Graph
    int N;
  
    // Constructor
    DynamicDisjointSetDS(int n)
    {
        N = n;
    }
  
    // Get Parent of vertex V
    int getParent(int vertex)
    {
  
        // If the vertex is already inserted 
        // in the graph
        if (parent.find(vertex) != parent.end()) {
  
            if (parent[vertex] != vertex) {
                parent[vertex] = 
                      getParent(parent[vertex]);
                return parent[vertex];
            }
        }
  
        // if the vertex is operated for the first
        // time
        else {
  
            // insert the vertex and assign its 
            // parent to itself
            parent.insert(make_pair(vertex, vertex));
  
            // Degree of the vertex
            degree.insert(make_pair(vertex, 1));
        }
  
        return vertex;
    }
  
    // Union by Rank
    void Union(int vertexA, int vertexB)
    {
        // Parent of Vertex A
        int x = getParent(vertexA);
  
        // Parent of Vertex B
        int y = getParent(vertexB);
  
        // if both have same parent
        // Do Nothing
        if (x == y)
            return;
  
        // Merging the componet
        // Assigning the parent of smaller Component
        // as the parent of the bigger Component.
        if (degree[x] > degree[y]) {
            parent[y] = x;
            degree[x] = degree[x] + degree[y];
        }
        else {
            parent[x] = y;
            degree[y] = degree[y] + degree[x];
        }
    }
  
    // Count total Component in the Graph
    int GetTotalComponent()
    {
        // To count the total Component formed 
        // from the inserted vertex in the Graph
        unordered_set total;
  
        // Iterate through the parent
        for (auto itr = parent.begin(); 
            itr != parent.end(); itr++) {
  
            // Add the parent of each Vertex
            // to the set
            total.insert(getParent(itr->first));
        }
  
        // Total Component = Total Vertexes -
        // Number of Vertex in the parent + 
        // Number of Component formed from 
        // the Vertexes inserted in the Graph
        return N - parent.size() + total.size();
    }
};
  
// Solve
void Solve()
{
  
    // Declaring the Dynamic Disjoint Set DS
    DynamicDisjointSetDS dsu(N);
  
    // Traversing through the Edges
    for (int i = 0; i < 3; i++) {
  
        // If the Vertexes in the Edges
        // have same parent do nothing
        if (dsu.getParent(Edges[i][0]) == 
            dsu.getParent(Edges[i][1])) {
            continue;
        }
  
        // else Do Union of both the Components.
        else {
            dsu.Union(Edges[i][0], Edges[i][1]);
        }
    }
  
    // Get total Components
    cout << dsu.GetTotalComponent();
}
  
// Driver Code
int main()
{
    // Total Number of Vertexes
    N = 5;
      
    /* Edges
    * 1 <--> 2 
    * 2 <--> 3 
    * 4 <--> 5    */
  
    Edges[0][0] = 1;
    Edges[0][1] = 2;
    Edges[1][0] = 2;
    Edges[1][1] = 3;
    Edges[2][0] = 4;
    Edges[2][1] = 3;
  
    // Solve
    Solve();
  
    return 0;
}


Python3
# Dynamic Disjoint Set Data Structure 
# Union-Find 
  
# Dynamic Disjoint Set Data Structure 
class DynamicDisjointSetDS: 
  
    # Constructor 
    def __init__(self, n): 
          
        # Total nomber of Vertex in the Graph 
        self.N = n
          
        # We will add the vertex to the edge 
        # only when it is asked to i.e. maintain 
        # a dynamic DS. 
        self.parent = {}
        self.degree = {}
  
    # Get Parent of vertex V 
    def getParent(self, vertex): 
      
        # If the vertex is already inserted 
        # in the graph 
        if vertex in self.parent: 
  
            if self.parent[vertex] != vertex: 
                self.parent[vertex] = \
                    self.getParent(self.parent[vertex]) 
                      
                return self.parent[vertex] 
  
        # if the vertex is operated 
        # for the first time 
        else:
  
            # insert the vertex and assign 
            # its parent to itself 
            self.parent[vertex] = vertex 
  
            # Degree of the vertex 
            self.degree[vertex] = 1
          
        return vertex 
      
    # Union by Rank 
    def Union(self, vertexA, vertexB): 
      
        # Parent of Vertex A 
        x = self.getParent(vertexA) 
  
        # Parent of Vertex B 
        y = self.getParent(vertexB) 
  
        # if both have same parent 
        # Do Nothing 
        if x == y: 
            return
  
        # Merging the componet 
        # Assigning the parent of smaller Component 
        # as the parent of the bigger Component. 
        if self.degree[x] > self.degree[y]: 
            self.parent[y] = x 
            self.degree[x] = (self.degree[x] + 
                              self.degree[y]) 
          
        else:
            self.parent[x] = y 
            self.degree[y] = (self.degree[y] + 
                              self.degree[x]) 
          
    # Count total Component in the Graph 
    def GetTotalComponent(self):
      
        # To count the total Component formed 
        # from the inserted vertex in the Graph 
        total = set() 
  
        # Iterate through the parent 
        for itr in self.parent: 
  
            # Add the parent of each Vertex 
            # to the set 
            total.add(self.getParent(itr)) 
          
        # Total Component = Total Vertexes - 
        # Number of Vertex in the parent + 
        # Number of Component formed from 
        # the Vertexes inserted in the Graph 
        return self.N - len(self.parent) + len(total) 
  
# Solve 
def Solve(N):
  
    # Declaring the Dynamic Disjoint Set DS 
    dsu = DynamicDisjointSetDS(N) 
  
    # Traversing through the Edges 
    for i in range(0, 3): 
  
        # If the Vertexes in the Edges 
        # have same parent do nothing 
        if (dsu.getParent(Edges[i][0]) ==
            dsu.getParent(Edges[i][1])): 
            continue
  
        # else Do Union of both the Components. 
        else:
            dsu.Union(Edges[i][0], Edges[i][1]) 
  
    # Get total Components 
    print(dsu.GetTotalComponent())
  
# Driver Code 
if __name__ == "__main__": 
  
    # Total Number of Vertexes 
    N = 5
    Edges = [[1, 2], [2, 3], [4, 3]]
  
    # Solve 
    Solve(N) 
  
# This code is contributed by 
# Rituraj Jain


输出:

2

注意:如果顶点数量更大,我们只需将数据类型从int更改为long long即可实现相同的代码。