1、幂集
所谓幂集(Power Set), 就是原集合中所有的子集(包括全集和空集)构成的集族。
可数集是最小的无限集; 它的幂集和实数集一一对应(也称同势),是不可数集。
不是所有不可数集都和实数集等势,集合的势可以无限的大。如实数集的幂集也是不可数集,但它的势比实数集大。
设X是一个有限集,|X| = k,则X的幂集的势为2的k次方。(摘自百度百科)
|X| 表示集合X中元素的个数。
首先了解下为什么幂集元素个数 = 2的k次方
设集合X = {a,b,c}
那么幂集为:
{}、{a}、{b}、{a,b}、{c}、{a,c}、{b,c}、{a,b,c}
将集合从成单元素慢慢到全集增长的过程就比较容易理解了
每增长一个元素组成的新的幂集 = 增长前的幂集 + 该元素与增长前幂集的组合
step1: X1 = {a}
幂集: {}、{a}
step2: X2 = {a,b}
幂集: {}、{a} + ({}{b} + {a}{b}) = {} 、{a}、{b}、{a,b}
step3: X3 = {a,b,c}
幂集:{} 、{a}、{b}、{a,b} + ({}{c} + {a}{c} + {b}{c} + {a,b}{c}) = {}、{a}、{b}、{a,b}、{c}、{a,c}、{b,c}、{a,b,c}
通过1、2、3可以看出一个规律 幂集生长的速度为 前一个幂集元素的个数 * 2
k = 1时 个数为 2 2^1
k = 2时 个数为 2*2 2^2
k = 3时 个数为 2*2*2 2^3
...
k = n时 个数为 2*2*2...*2 2^n
2、算法实现
2.1 实现一 组合法
通过上面step1、2、3的规律可以写一个很直观的求出幂集
下面是用java集合实现
public class PowerSetArith {
public List<List<String>> powerSet(List<String> set) {
int size = 2 << set.size();
List<List<String>> powerSet = new ArrayList<>(size);
powerSet.add(Collections.emptyList());
for (String element : set) {
int preSize = powerSet.size();
for (int i = 0; i < preSize; i++) {
List<String> combineSubset = new ArrayList<>(powerSet.get(i));
combineSubset.add(element);
powerSet.add(combineSubset);
}
}
return powerSet;
}
@Test
public void testPowerSet() {
List<String> set = Arrays.asList("a", "b", "c", "d");
List<List<String>> powerSet = powerSet(set);
System.out.println(Arrays.toString(powerSet.toArray()));
}
}
上面的方法也可以使用数组代替集合实现
2.2 实现二 位图法
由于n个元素集合的幂集个数 是2^n,而n个二进制位的最大值等于 = 2^n - 1,算上0的话正好2^n个数值
而此时元素的个数n刚好与二进制数的位数相等,0刚好可以用来表示空集,因此可以作一个函数f(n)来描述0~2^n-1 的数进行一一对应。
例如
集合X = {a,b,c}
取二进制数2^3 - 1 = 7 与之对应
7的二进制表示为:111
0~7的过程为:
000 001 010 011 100 101 110 111
那么f(n)怎么定义就能一一对应了呢?
从上面的数字中可以找到规律,位数正好等于集合中元素的个数,可以将二进制数的位与集合中元素的角标对应起来,
再者通过所在位的值是1 还是 0 来决定对位元素是否存在,这样根据0~2^n-1 的位图组合对应出的一个新的集合就是对应集合的幂集了。
java实现算法:
public class PowerSetArith {
public List<List<String>> bitPowerSet(List<String> set) {
int bitmapMaxNum = 2 << (set.size() - 1);
List<List<String>> powerSet = new ArrayList<>(2 << set.size());
powerSet.add(Collections.emptyList());
for (int i = 1; i < bitmapMaxNum; i++) {
powerSet.add(subset(set, i));
}
return powerSet;
}
public List<String> subset(List<String> set, int bitMapNum) {
List<String> subset = new ArrayList<>();
for (int i = 0; i < set.size(); i++) {
if (((bitMapNum >> i) & 1) == 1) {
subset.add(set.get(i));
}
}
return subset;
}
@Test
public void testBitPowerSet() {
List<String> set = Arrays.asList("a", "b", "c", "d");
List<List<String>> powerSet = bitPowerSet(set);
System.out.println(Arrays.toString(powerSet.toArray()));
}
}