简体   繁体   English

获取集合的所有子集

[英]Get all subsets of a set

import java.util.ArrayList;

public class Subset { //Generate all subsets by generating all binary numbers
    public static ArrayList<ArrayList<Integer>> getSubsets2(ArrayList<Integer> set) {

        ArrayList<ArrayList<Integer>> allsubsets =
            new ArrayList<ArrayList<Integer>>();
        int max = 1 << set.size();             //there are 2 power n 
        for (int i = 0; i < max; i++) {
            ArrayList<Integer> subset = new ArrayList<Integer>();

            int index = 0;
            while (i > 0) {
                if ((i & 1) > 0) {
                    subset.add(set.get(index)); //Add elements to a new ArrayList
                }
                i >>= 1;
                index++;
            }
            allsubsets.add(subset);
        }
        return allsubsets;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ArrayList<Integer> set = new ArrayList<Integer>(); //Create an ArrayList
        set.add(1);
        set.add(2);

        System.out.println(getSubsets2(set));
    }
}

The result should be [[],[1],[2],[1,2]] 结果应该是[[],[1],[2],[1,2]]

But I can't get the result, the exception is as follows: 但我无法得到结果,例外情况如下:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Your while loop is incorrect. 你的while循环不正确。

Made slightly more succinct with a for-loop: 使用for循环稍微简洁一点:

import java.util.ArrayList;

public class Subset { //Generate all subsets by generating all binary numbers
    public static ArrayList<ArrayList<Integer>> getSubsets2(ArrayList<Integer> set) {

        ArrayList<ArrayList<Integer>> allsubsets =
        new ArrayList<ArrayList<Integer>>();
        int max = 1 << set.size();             //there are 2 power n different subsets

        for (int i = 0; i < max; i++) {
            ArrayList<Integer> subset = new ArrayList<Integer>();
            for (int j = 0; j < set.size(); j++) {
                if (((i >> j) & 1) == 1) {
                    subset.add(set.get(j));
                }
            }
            allsubsets.add(subset);
        }
        return allsubsets;
    }

    public static void main(String[] args) {
        ArrayList<Integer> set = new ArrayList<Integer>(); //Create an ArrayList
        set.add(1);
        set.add(2);

        System.out.println(getSubsets2(set));
    }
}

Bear in mind that the subset operation is exponential, so you'll get a very large number of elements. 请记住,子集操作是指数级的,因此您将获得大量元素。 The implementation above will only work with about 32 input elements, as that yields 2^32 output subsets, which will very easily run you over the limit of an array... 上面的实现只适用于大约32个输入元素,因为它产生2 ^ 32个输出子集,这将非常容易地超过数组的限制...

Your problem appears to be in your loop. 你的问题似乎在你的循环中。 If you look at it: 如果你看一下:

for (int i = 0; i < max; i++) {
    ArrayList<Integer> subset = new ArrayList<Integer>();
    int index = 0;
    while (i > 0) {
        if ((i & 1) > 0) {
            subset.add(set.get(index)); //Add elements to a new ArrayList
        }
        i >>= 1;
        index++;
    }
    allsubsets.add(subset);
}

You'll notice that the outside for-loop is trying to count i upwards from zero, and the inner while loop counts it back to zero every iteration, so the outer loop runs forever. 你会注意到外部for循环试图从零向上计数i ,而内部while循环在每次迭代时将其计数回零,因此外循环永远运行。

Program runs forever. 程序永远运行。 Below statement execute continuesly and getting outOfMemory. 下面的语句继续执行并获取outOfMemory。 Variable i value is never bigger than max value, check it. 变量i值永远不会大于最大值,请检查它。

`subset.add(set.get(index));` 

In a nutshell, your inner while-loop is changing the outer for-loop's loop variable ( i ). 简而言之,你的内部while循环正在改变外部for循环的循环变量( i )。 This is disrupting the outer loop iteration. 这会破坏外循环迭代。 At the end of the inner loop the value of i is going to be zero ... which means that the outer loop will never terminate. 在内循环结束时, i的值将为零...这意味着外循环永远不会终止。

Given what you are doing, the fix is to use a different variable (say j ) for the inner loop, and initialize it from i . 鉴于你正在做什么,修复是为内循环使用不同的变量(比如j ),并从i初始化它。


This illustrates why it is a bad idea to change a for-loop variable inside the loop. 这说明了为什么在循环中更改for循环变量是个坏主意。

how about a recursive solution? 递归解决方案怎么样?

vector<vector<int> > getSubsets(vector<int> a){


//base case
    //if there is just one item then its subsets are that item and empty item
    //for example all subsets of {1} are {1}, {}

    if(a.size() == 1){
        vector<vector<int> > temp;
        temp.push_back(a);

        vector<int> b;
        temp.push_back(b);

        return temp;

    }
    else
    {


         //here is what i am doing

         // getSubsets({1, 2, 3})
         //without = getSubsets({1, 2})
         //without = {1}, {2}, {}, {1, 2}

         //with = {1, 3}, {2, 3}, {3}, {1, 2, 3}

         //total = {{1}, {2}, {}, {1, 2}, {1, 3}, {2, 3}, {3}, {1, 2, 3}}

         //return total

        int last = a[a.size() - 1];

        a.pop_back();

        vector<vector<int> > without = getSubsets(a);

        vector<vector<int> > with = without;

        for(int i=0;i<without.size();i++){

            with[i].push_back(last);

        }

        vector<vector<int> > total;

        for(int j=0;j<without.size();j++){
            total.push_back(without[j]);
        }

        for(int k=0;k<with.size();k++){
            total.push_back(with[k]);
        }


        return total;
    }


}

Here is a Java 8 solution for this question: 以下是针对此问题的Java 8解决方案:

public Set<Set<Integer>> getSubsets(Set<Integer> set) {
    if (set.isEmpty()) {
       return Collections.singleton(Collections.emptySet());
    }

    Set<Set<Integer>> subSets = set.stream().map(item -> {
        Set<Integer> clone = new HashSet<>(set);
        clone.remove(item);
        return clone;
    }).map(group -> getSubsets(group))
            .reduce(new HashSet<>(), (x, y) -> {
                x.addAll(y);
                return x;
            });

    subSets.add(set);
    return subSets;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM