zoukankan      html  css  js  c++  java
  • Union-find 并查集

    解决问题

    给一系列对点0~N-1的连接,判断某两个点p与q是否相连。

    private int[] id;
    
    // 判断p和q是否属于同一个连通分量
    public boolean connected(int p, int q) 
    
    // 连接两个点
    public void union(int p, int q)
    

      

    Quick-find

    connected(p, q):判断p 和 q 的id值是否相同

    union(p, q): 将与p 的id 相同的所有点都改为q的id

    缺点:union太慢,需要遍历id数组

    Quick-union

    connected(p, q):判断p 和 q 的根的id值是否相同

    union(p, q): 将与p 的根的 id 改为q的根的 id

    本质上是将并查集之间的关系看做一棵树

    缺点:最坏情况下仍然需要遍历数组

    Weighted Quick-union

    connected(p, q):判断p 和 q 的根的id值是否相同

    union(p, q): 判断p和q所在的树哪个大(包含的节点多),将较小的树根的 id 改为较大的树根的 id

    某个节点高度增加1,当且仅当它在一颗小树T1上且被union并入大树T2中,生成的树节点数大于T1的两倍,所以某个节点的高度最多只能是lg(N)

    Weighted Quick-union with Path Compression

    connected(p, q):判断p 和 q 的根的id值是否相同

    union(p, q): 判断p和q所在的树哪个大(包含的节点多),将较小的节点到较小的树根这条路径上所有节点的 id 改为较大的树根的 id

    总结

    四种方法复杂度如下,其中lg* 表示需要取对数多少次才能将N的值变为≤1,WQUPC复杂度是由论文中所得,lg*可以视为常数复杂度。

    algorithm 初始化 union connected
    quick find N N 1
    quick union N N N
    weighted quick union N lg N lg N
    weighted quick union with path compression N lg* N lg* N

     实现

    public class UF {
    
        private int[] parent;  // parent[i] = parent of i
        private byte[] rank;   // rank[i] = rank of subtree rooted at i (never more than 31) 记录的是树的高度
        private int count;     // number of components
    
        /**
         * Initializes an empty union-find data structure with <tt>N</tt> sites
         * <tt>0</tt> through <tt>N-1</tt>. Each site is initially in its own 
         * component.
         *
         * @param  N the number of sites
         * @throws IllegalArgumentException if <tt>N < 0</tt>
         */
        public UF(int N) {
            if (N < 0) throw new IllegalArgumentException();
            count = N;
            parent = new int[N];
            rank = new byte[N];
            for (int i = 0; i < N; i++) {
                parent[i] = i;
                rank[i] = 0;
            }
        }
    
        /**
         * Returns the component identifier for the component containing site <tt>p</tt>.
         *
         * @param  p the integer representing one site
         * @return the component identifier for the component containing site <tt>p</tt>
         * @throws IndexOutOfBoundsException unless <tt>0 ≤ p < N</tt>
         */
        public int find(int p) {
            validate(p);
            while (p != parent[p]) {
                parent[p] = parent[parent[p]];    // path compression by halving 【完成路径压缩】
                p = parent[p];
            }
            return p;
        }
    
        /**
         * Returns the number of components.
         *
         * @return the number of components (between <tt>1</tt> and <tt>N</tt>)
         */
        public int count() {
            return count;
        }
      
        /**
         * Returns true if the the two sites are in the same component.
         *
         * @param  p the integer representing one site
         * @param  q the integer representing the other site
         * @return <tt>true</tt> if the two sites <tt>p</tt> and <tt>q</tt> are in the same component;
         *         <tt>false</tt> otherwise
         * @throws IndexOutOfBoundsException unless
         *         both <tt>0 ≤ p < N</tt> and <tt>0 ≤ q < N</tt>
         */
        public boolean connected(int p, int q) {
            return find(p) == find(q);
        }
      
        /**
         * Merges the component containing site <tt>p</tt> with the 
         * the component containing site <tt>q</tt>.
         *
         * @param  p the integer representing one site
         * @param  q the integer representing the other site
         * @throws IndexOutOfBoundsException unless
         *         both <tt>0 ≤ p < N</tt> and <tt>0 ≤ q < N</tt>
         */
        public void union(int p, int q) {
            int rootP = find(p);
            int rootQ = find(q);
            if (rootP == rootQ) return;
    
            // make root of smaller rank point to root of larger rank
            if      (rank[rootP] < rank[rootQ]) parent[rootP] = rootQ;
            else if (rank[rootP] > rank[rootQ]) parent[rootQ] = rootP;
            else {
                parent[rootQ] = rootP;
                rank[rootP]++; //【只有此处才增加联通分量的rank】
            }
            count--;
        }
    
        // validate that p is a valid index
        private void validate(int p) {
            int N = parent.length;
            if (p < 0 || p >= N) {
                throw new IndexOutOfBoundsException("index " + p + " is not between 0 and " + (N-1));  
            }
        }
    
        /**
         * Reads in a an integer <tt>N</tt> and a sequence of pairs of integers
         * (between <tt>0</tt> and <tt>N-1</tt>) from standard input, where each integer
         * in the pair represents some site;
         * if the sites are in different components, merge the two components
         * and print the pair to standard output.
         */
        public static void main(String[] args) {
            int N = StdIn.readInt();
            UF uf = new UF(N);
            while (!StdIn.isEmpty()) {
                int p = StdIn.readInt();
                int q = StdIn.readInt();
                if (uf.connected(p, q)) continue;
                uf.union(p, q);
                StdOut.println(p + " " + q);
            }
            StdOut.println(uf.count() + " components");
        }
    }
    

      

  • 相关阅读:
    mysql的小练习
    实用IMX6开发板来袭, 方便开发板方便你
    又到开学季 学习神器走一波 物联网开发板
    如何修改开发板主频--迅为iMX6UL开发板
    迅为4412开发板实战之智能网关项目
    iTOP-iMX6开发板Android系统下LVDS和HDMI双屏异显方法
    恩智浦iMX6Q核心板/飞思卡尔Cortex-A9高稳定性低功耗开发板
    嵌入式ARM开发板学习方法步骤
    迅为iMX6UL Cortex-A7架构单核ARM开发板接口介绍-支持定制
    三星系列NXP系列核心板设计研发-迅为嵌入式ARM方案提供商
  • 原文地址:https://www.cnblogs.com/ericxing/p/4402725.html
Copyright © 2011-2022 走看看