Java算法學習:求取一個集合中的所有子集

 求取一個集合中的所有子集

package 算法學習;

import java.util.HashSet;
import java.util.Set;

/**
 * Page Description:
 * User: Yelihu
 * Date: 2019-03-02
 * Time: 下午 3:02
 * Function:
 */
public class 增量迭代 {
    private static int[] array = {1,2,0,4};

    private static Set<Set<Integer>> handler(int[] array,int n){
        return getSubSetCore(array,n,n-1);
    }

    private static Set<Set<Integer>> getSubSetCore(int[] array,int n,int cur){
        //創建一個集合存放原來集合+加上增量集合
        Set<Set<Integer>> newSet = new HashSet<>();
        if(cur==0){
            Set<Integer> nullSet = new HashSet<>();
            Set<Integer> firstSet = new HashSet<>();
            firstSet.add(array[0]);
            newSet.add(firstSet);
            newSet.add(nullSet);
            return newSet;
        }
        //獲取到原來集合
        Set<Set<Integer>> oldSet = getSubSetCore(array,n,cur-1);
        //從老集合中獲取到一個個數字,拷貝出來加入新的集合
        for (Set<Integer> set: oldSet) {
            newSet.add(set);
            Set<Integer> clone = (Set<Integer>) ((HashSet)set).clone();
            clone.add(array[cur]);
            newSet.add(clone);
        }
        return newSet;
    }

    public static void main(String[] args) {
        Set<Set<Integer>> sets = handler(array,array.length);
        System.out.println(sets);
    }
}

帶註釋解析版本

import java.util.HashSet;
import java.util.Set;

public class Main {

    public static void main(String[] args) {
        int[] A = {1,2,3};
        System.out.println(A.length);
        Set<Set<Integer>> subSets = new Main().getSubset3(A,A.length);
        System.out.println(subSets);
    }

    private Set<Set<Integer>> getSubset3(int[] A,int n){
        return getSubsets3Core(A,n,n-1);
    }

    /**
     * 遞歸增量構造法
     * @param A
     * @param n
     * @param cur
     * @return
     */
    private Set<Set<Integer>> getSubsets3Core(int[] A,int n,int cur ){
        Set<Set<Integer>> newSet =  new HashSet<>();

        //如果cur==0,那麼在處理第一個元素
        if(cur==0){
            //空集
            Set<Integer> nil = new HashSet<>();
            //包含第一個元素的集合
            Set<Integer> first = new HashSet<>();
            first.add(A[0]);
            newSet.add(nil);
            newSet.add(first);
            return newSet;
        }

       Set<Set<Integer>> oldSet =  getSubsets3Core(A,n,cur-1);
        for (Set<Integer> set:oldSet) {
            //對於每個子集來說,cur這個元素,可以加入也可以不加入
            //set就是oldSet裏面的一個子集,把它取出來,放在newSet裏面,比如說是[1]
            newSet.add(set);
            //克隆之前取出的子集元素set,叫做clone,也就是說新的一個set,名字叫clone,內容是[1]
            Set<Integer> clone = (Set<Integer>) ((HashSet)set).clone();
            //clone加入增量元素,這個元素從數組中取出,遞歸每回溯一次,就會加入新的元素
            //這個時候clone的內容是,[1,2]
            clone.add(A[cur]);
            //向newSet裏面添加clone,整個過程,newSet的添加順序是,[空集],[2],[1][1,2].
            newSet.add(clone);
        }
        return newSet;
    }

}

注意點:在java中的set,空集加入一個元素之後,就是元素本身,比如我用null表示空集,原來一個set是[null],add了一個2之後,實際上這個set就變成了[2],而不是[null,2]。

//在這個過程中,作爲全部子集的集合newSet是如何一步步的補全的,我們可以把它看作一棵類似二叉樹的過程,每個節點在下一次getSubSetCore函數調用的時候,都會向下產生兩個分支,一個是節點原來的樣子,變成這個節點的一個子節點,另一個是加上從數組中取出來的新的元素之後的節點。

如下圖所示,左邊我標註了是在取出數組第幾個,右邊表示的三次調用getSubSetCore函數之後,newSet的補全的過程

 

  //後續複習的時候會繼續補充說明

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章