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的补全的过程

 

  //后续复习的时候会继续补充说明

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