interface UF
{
    int getSize();
    bool isConnected(int p, int q);
    void unionElements(int p, int q);
}
public class QuickUnionFind : UF
{
    private int[] parent;
    private int[] rank;

    public QuickUnionFind(int size)
    {
        parent = new int[size];
        rank = new int[size];
        for (var i = 0; i < size; i++)
        {
            parent[i] = i;
            rank[i] = 1;
        }
    }

    public int getSize()
    {
        return parent.Length;
    }
    /// <summary>
    /// 查找过程 查找元素p所对应的集合编号
    /// O(h)复杂度 h为树的高度
    /// </summary>
    /// <param name="p"></param>
    /// <returns></returns>
    private int find2(int p)
    {
        if (p < 0 || p >= parent.Length)
            throw new System.Exception("p is out of bound");
        while (p != parent[p])
        {
            //路径压缩
            parent[p] = parent[parent[p]];
            p = parent[p];
        }
        return p;
    }
    /// <summary>
    /// 查找过程 查找元素p所对应的集合编号
    /// O(h)复杂度 h为树的高度
    /// </summary>
    /// <param name="p"></param>
    /// <returns></returns>
    private int find(int p)
    {
        if (p < 0 || p >= parent.Length)
            throw new System.Exception("p is out of bound");
        if (p != parent[p])
        {
            // 递归 内部运行 路径压缩  
            parent[p] = find(parent[p]);
        }
        return parent[p];
    }
    /// <summary>
    /// 查看元素p和q是否所属一个集合
    /// O(h)复杂度  h为树的高度
    /// </summary>
    /// <param name="p"></param>
    /// <param name="q"></param>
    /// <returns></returns>
    public bool isConnected(int p, int q)
    {
        return find(p) == find(q);
    }

    public void unionElements(int p, int q)
    {
        int pRoot = find(p);
        int qRoot = find(q);
        if (pRoot == qRoot) return;
        //根据两个元素所在树的rank不同判断合并方向
        //讲rank低的集合合并到runk高的集合上
        if (rank[pRoot] < rank[qRoot])
        {
            parent[pRoot] = qRoot;
        }
        else if (rank[qRoot] < rank[pRoot])
        {
            parent[qRoot] = pRoot;
        }
        else
        {
            parent[qRoot] = pRoot;
            rank[pRoot] += 1;
        }
    }



}

路径压缩find2

C# 实现并查集_复杂度