1. 程式人生 > >java演算法例項_合併元素&&判斷元素是否連通

java演算法例項_合併元素&&判斷元素是否連通

案例1:簡單的實現方式,直接遍歷

程式碼:

package me.ele.union_find;

import java.util.Arrays;
import java.util.List;

/**
 * 快速查詢 UC(union find)
 * <p>
 * 有一些元素 a b c d e f g h ......
 *
 * @author LZJ
 * @create 2018-10-03 13:40
 **/
public class QuickFindUF {
    private int[] idArr;

    /**
     * 初始化 陣列,陣列中每個位置上元素的值 即 元素的下標
     *
     * @param n
     */
    public QuickFindUF(int n) {
        idArr = new int[n];
        for (int i = 0; i < n; i++) {
            idArr[i] = i;
        }
    }

    /**
     * 給定兩個元素,查詢兩個元素是否在統一集合內
     *
     * @param p
     * @param q
     * @return 如果兩個元素在陣列中的值 相等,即代表兩個元素連通
     */
    public boolean find(int p, int q) {
        return idArr[p] == idArr[q];
    }

    /**
     * 合併兩個元素 即 將兩個元素連通
     * 每次合併 兩個元素的時候,遍歷當前陣列,將其中所有符合(值與p元素的值相等的)所有元素 替換為q的值
     * 這樣,p元素以及之前的符合條件的元素 都會與q元素合併(連通)
     *
     * @param p
     * @param q
     */
    public void union(int p, int q) {
        int length = idArr.length;
        for (int i = 0; i < length; i++) {
            if (idArr[i] == idArr[p]) {
                idArr[i] = idArr[q];
            }
        }
    }
}

測試:

public static void main(String[] args) {
    // [0-9]十個元素放置到陣列 idArr 之所以使用0-9不重複的數字 是因為想要唯一區分每個元素
    QuickFindUF quickFindUF = new QuickFindUF(10);

    System.out.println("------- 合併(連通)元素:1和2 -------");
    quickFindUF.union(1, 2);
    System.out.println("合併後å陣列id:" + Arrays.toString(quickFindUF.idArr));

    System.out.println("------- 合併(連通)元素:2和3 -------");
    quickFindUF.union(2, 3);
    System.out.println("陣列id:" + Arrays.toString(quickFindUF.idArr));

    System.out.println("------- 合併(連通)元素:4和5 -------");
    quickFindUF.union(4, 5);
    System.out.println("陣列id:" + Arrays.toString(quickFindUF.idArr));
    System.out.println("========");

    System.out.println("元素:1和2是否連通-->" + quickFindUF.find(1, 2));

    System.out.println("元素:1和4是否連通-->" + quickFindUF.find(1, 4));

    System.out.println("元素:4和5是否連通-->" + quickFindUF.find(4, 5));

}

執行結果:

案例2:通過 根的方式區分元素是否在同一集合

程式碼:

package me.ele.union_find;

import java.util.Arrays;

/**
 * 上一個 QuickFindUF演算法 合併元素的時候,將所有元素的直接連在一起
 * 在本QuickUnionUF中,將會區分root節點  root節點一致的兩個元素是連通的
 *
 * @author LZJ
 * @create 2018-10-03 14:29
 **/
public class QuickUnionUF {
    private int[] idArr;

    public QuickUnionUF(int n) {
        idArr = new int[n];
        for (int i = 0; i < n; i++) {
            idArr[i] = i;
        }
    }

    public int root(int p) {
        while (idArr[p] != p) {
            p = idArr[p];
        }
        return p;
    }

    public void union(int p, int q) {
        int root_p = root(p);
        int root_q = root(q);
        idArr[root_p] = root_q;
    }

    public boolean find(int p, int q) {
        return root(p) == root(q);
    }
}

測試:

public static void main(String[] args) {
    QuickUnionUF quickUnionUF = new QuickUnionUF(10);
    System.out.println(Arrays.toString(quickUnionUF.idArr));

    System.out.println("------- 合併1 和 2:-------");
    quickUnionUF.union(1, 2);
    System.out.println(Arrays.toString(quickUnionUF.idArr));
    System.out.println("判斷 1 和2 是否連通:");
    System.out.println(quickUnionUF.find(1, 2));

    System.out.println("------- 合併2 和 4:-------");
    quickUnionUF.union(2, 4);
    System.out.println(Arrays.toString(quickUnionUF.idArr));
    System.out.println("判斷 2 和4 是否連通:");
    System.out.println(quickUnionUF.find(2, 4));

    System.out.println("1 的根:" + quickUnionUF.root(1));
    System.out.println("判斷 1 和4 是否連通:");
    System.out.println(quickUnionUF.find(1, 4));
    
}

執行結果:

案例3: 在案例2的基礎上新增權重

程式碼:

package me.ele.union_find;

import java.util.Arrays;

/**
 * 有root並且 帶權重的 合併
 * @author LZJ
 * @create 2018-10-03 14:46
 **/
public class WeightUnionUF {
    int[] idArr;
    int[] weight;

    public WeightUnionUF(int n) {
        idArr = new int[n];
        weight = new int[n];
        for (int i = 0; i < n; i++) {
            idArr[i] = i;
            weight[i] = 1;
        }
    }

    private int root(int p) {
        while (idArr[p] != p) {
            idArr[p] = idArr[idArr[p]];
            p = idArr[p];
        }
        return p;
    }

    public void union(int p, int q) {
        int root_p = root(p);
        int root_q = root(q);
        if (weight[root_q] >= weight[root_p]) {
            idArr[root_p] = root_q;
            weight[root_q] += weight[root_p];
            weight[root_p] = 0;
        } else {
            idArr[root_q] = root_p;
            weight[root_p] += weight[root_q];
            weight[root_q] = 0;
        }
    }

    public boolean find(int p, int q) {
        return root(p) == root(q);
    }
}

測試:

public static void main(String[] args) {
    WeightUnionUF weightUnionUF = new WeightUnionUF(10);

    System.out.println("idArr:"+ Arrays.toString(weightUnionUF.idArr));
    System.out.println("weight:"+ Arrays.toString(weightUnionUF.weight));

    System.out.println("-----合併 1 和 3-----");
    weightUnionUF.union(1,3);
    System.out.println("idArr:"+ Arrays.toString(weightUnionUF.idArr));
    System.out.println("weight:"+ Arrays.toString(weightUnionUF.weight));
    System.out.println("1 和 3是否連通:"+weightUnionUF.find(1,3));

    System.out.println("-----合併 1 和 4-----");
    weightUnionUF.union(1,4);
    System.out.println("idArr:"+ Arrays.toString(weightUnionUF.idArr));
    System.out.println("weight:"+ Arrays.toString(weightUnionUF.weight));
    System.out.println("1 和 3是否連通:"+weightUnionUF.find(1,3));
    System.out.println("1 和 4是否連通:"+weightUnionUF.find(1,4));
    System.out.println("3 和 4是否連通:"+weightUnionUF.find(3,4));

    System.out.println("-----合併 3 和 4-----");
    weightUnionUF.union(3,4);
    System.out.println("idArr:"+ Arrays.toString(weightUnionUF.idArr));
    System.out.println("weight:"+ Arrays.toString(weightUnionUF.weight));
    System.out.println("1 和 3是否連通:"+weightUnionUF.find(1,3));
    System.out.println("1 和 4是否連通:"+weightUnionUF.find(1,4));
    System.out.println("3 和 4是否連通:"+weightUnionUF.find(3,4));

}

執行結果: