首先,幂集:
对于 n 个不同的元素,您可以创建 2n 个集合,当考虑“这个元素是否包含在这个特定集合中?”这个问题时可以很容易地显示出来。一个布尔值:
对于 n=3:
0: 0 0 0 none included
1: 0 0 1 first included
2: 0 1 0 second included
3: 0 1 1 first and second one included
4: 1 0 0 third included
5: 1 0 1 first and third included
6: 1 1 0 second and third included
7: 1 1 1 all included
因此,可以通过迭代从 0 到 2ⁿ 的整数并使用每个数字的位模式从原始集合中选择元素来实现对所有组合的迭代(我们必须将它们复制到像 @987654322 这样的有序结构中@为此):
public static <T> Set<Set<T>> allPermutations(Set<T> input) {
List<T> sequence = new ArrayList<>(input);
long count = sequence.size() > 62? Long.MAX_VALUE: 1L << sequence.size();
HashSet<Set<T>> result = new HashSet<>((int)Math.min(Integer.MAX_VALUE, count));
for(long l = 0; l >= 0 && l < count; l++) {
if(l == 0) result.add(Collections.emptySet());
else if(Long.lowestOneBit(l) == l)
result.add(Collections.singleton(sequence.get(Long.numberOfTrailingZeros(l))));
else {
HashSet<T> next = new HashSet<>((int)(Long.bitCount(l)*1.5f));
for(long tmp = l; tmp != 0; tmp-=Long.lowestOneBit(tmp)) {
next.add(sequence.get(Long.numberOfTrailingZeros(tmp)));
}
result.add(next);
}
}
return result;
}
然后
Set<String> input = new HashSet<>();
Collections.addAll(input, "1", "2", "3");
System.out.println(allPermutations(input));
给我们
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
要利用它来识别分区,我们必须扩展逻辑以使用计数器的位从另一个掩码中选择位,这将识别要包含的实际元素。然后,我们可以重复使用相同的操作来获取到目前为止未包含的元素的分区,使用一个简单的二元非操作:
public static <T> Set<Set<Set<T>>> allPartitions(Set<T> input) {
List<T> sequence = new ArrayList<>(input);
if(sequence.size() > 62) throw new OutOfMemoryError();
return allPartitions(sequence, (1L << sequence.size()) - 1);
}
private static <T> Set<Set<Set<T>>> allPartitions(List<T> input, long bits) {
long count = 1L << Long.bitCount(bits);
if(count == 1) {
return Collections.singleton(new HashSet<>());
}
Set<Set<Set<T>>> result = new HashSet<>();
for(long l = 1; l >= 0 && l < count; l++) {
long select = selectBits(l, bits);
final Set<T> first = get(input, select);
for(Set<Set<T>> all: allPartitions(input, bits&~select)) {
all.add(first);
result.add(all);
}
}
return result;
}
private static long selectBits(long selected, long mask) {
long result = 0;
for(long bit; selected != 0; selected >>>= 1, mask -= bit) {
bit = Long.lowestOneBit(mask);
if((selected & 1) != 0) result |= bit;
}
return result;
}
private static <T> Set<T> get(List<T> elements, long bits) {
if(bits == 0) return Collections.emptySet();
else if(Long.lowestOneBit(bits) == bits)
return Collections.singleton(elements.get(Long.numberOfTrailingZeros(bits)));
else {
HashSet<T> next = new HashSet<>();
for(; bits != 0; bits-=Long.lowestOneBit(bits)) {
next.add(elements.get(Long.numberOfTrailingZeros(bits)));
}
return next;
}
}
那么,
Set<String> input = new HashSet<>();
Collections.addAll(input, "1", "2", "3");
System.out.println(allPartitions(input));
给我们
[[[1], [2], [3]], [[1], [2, 3]], [[2], [1, 3]], [[3], [1, 2]], [[1, 2, 3]]]
而
Set<String> input = new HashSet<>();
Collections.addAll(input, "1", "2", "3", "4");
for(Set<Set<String>> partition: allPartitions(input))
System.out.println(partition);
产量
[[1], [3], [2, 4]]
[[1], [2], [3], [4]]
[[1], [2], [3, 4]]
[[1], [4], [2, 3]]
[[4], [1, 2, 3]]
[[1], [2, 3, 4]]
[[2], [3], [1, 4]]
[[2], [4], [1, 3]]
[[1, 2, 3, 4]]
[[1, 3], [2, 4]]
[[1, 4], [2, 3]]
[[2], [1, 3, 4]]
[[3], [1, 2], [4]]
[[1, 2], [3, 4]]
[[3], [1, 2, 4]]