Fork me on GitHub

Quick Union

1.Problem

Quick Union is a useful method to solve the dynamic connectivity problem, which can also be solved by depth-first search or breadth-first search.

2.Quick Union

  • Data structure

    Integer array id[] of length N

    id[i] is the parent of i, and to find the root of i, you are supposed to keep going until the parent doesn't change.

  • API

    Connected(p,q) To judge whether p and q have the same root.
    Find(p) To find the root of p.
    Union(p,q) Set the id of p's root to the id of q's root.
  • Code

    int find(int p){
        while(p!=id[p]){
            p = id[p];
        }
        return p;
    }
    
    bool connected(int p,int q){
        return find(p)==find(q);
    }
    
    void Union(int p,int q){
        int idp = find(p);
        int idq = find(q);
        if(connected(p,q)){
            return;
        }
        id[idp] = idq;
        count --;
    }
    

3.Improvements

3.1 Weighting quick union

  • Idea

    Balance by linking root of smaller tree to the root of lager tree

  • Data structure

    Maintain extra array sz[] to count number of objects in the tree.

  • Code

    void Union(int p,int q){
        int idp = find(p);
        int idq = find(q);
        if(connected(p,q)){
            return;
        }
        if(sz[idp]<sz[idq]){
            id[idp] = idq;
            sz[idq] += sz[idp];
        }else{
            id[idq] = idp;
            sz[idp] += sz[idq];
        }
        count --;
    }
    
  • Summary

Through this improvement, run time can be reduced sharply from 2984ms to 52ms when the quick union is applied the 130th problem in the leetcode.

3.2 Path compression

  • Idea

    When finding the node, just after computing the root of p, set the id[] of each examined node to point to that root.

  • Code

    int find(int p){
        int temp = p;
        while(p!=id[p]){
            p = id[p];
        }
        id[temp] = p;
        return p;
    }
    

3.3 Relationship between nodes

Quick Union only tells whether the two nodes belong to the same set, which in most case is enough to solve the problem. However, when there is a relative relationship between the nodes, another array should be introduced. For example, in POJ-1182, the food chain relationship between two nodes is needed. So, the data structure:

  • Data Structure

    Maintain extra array relation[] to record the relationship between node p and its root.

In addition, the process of union and find should be adjusted. When compressing the path and connecting two nodes, the array relation[] may also change correspondingly. Specifically, the relationship transfer can be listed as follows:

  • (A,B),(B,C) ---> (A,C)

    When finding the root of node p, we know the relationship between p and its current root id[p], as well as the relationship between id[p] and its root. We can then obtain the relationship between p and its root recursively.

  • (A,C),(B,C)->(A,B)

    When querying the relationship between node p and node q, we can infer it through the relationship between p,q and their root.

  • (A,B),(A,C)->(B,C)

    When connecting two trees, the relationships between node p and its root, node q and its root, p and q are known. And the relationship between node p's root and node q's root is needed. We can first find the relationship between p and the root of q through the relationship transfer (p,q),(q,q's root)->(p,q's root). And then (p's root, q's root) can be inferred through (p, p's root) and (p, q's root).

4. Reference

  1. Algorithms, 4th Edition,princeton
  2. https://agatelee.cn/2017/05/带权并查集/
posted @ 2019-02-18 13:27  Giggle221b  阅读(162)  评论(0编辑  收藏  举报