给定一组我想显示其所有子集(其功率集)。我找到了这段代码:
void printPowerSet(char *set, int set_size)
{
/*set_size of power set of a set with set_size
n is (2**n -1)*/
unsigned int pow_set_size = pow(2, set_size);
int counter, j;
/*Run from counter 000..0 to 111..1*/
for(counter = 0; counter < pow_set_size; counter++)
{
for(j = 0; j < set_size; j++)
{
if(counter & (1<<j))
printf("%c", set[j]);
}
printf("\n");
}
}
我无法理解为什么使用这部分
if(counter & (1<<j))
它的含义是什么?
此算法的时间复杂度为O(n2^n)
是否有更好的方法?
答案 0 :(得分:4)
此if
检查是否设置了位j
。例如,当我们查看j == 0
时(为简单起见,我使用的是8位):
XXXXXXX? & 00000001
其中X
是“不关心”,?
是我们想要检查的内容。然后是j == 1
XXXXXX?X & 00000010
换句话说,检查是否设置了一个位是一种方便的方法,它确定相应的set元素是否包含在当前集中。
至于复杂性,由于幂集中有2^n
个集合,因此很难想象用于生成所有集合的更快的算法。
这会产生一个功率集的原因是二进制计数器耗尽了n
位值的所有组合,请参阅以下示例。
<强> 实施例 强>
设置:{1,2,3}
counter 1<<j intermediate result final
000 001 N/A
000 010 N/A
000 100 N/A
{}
001 001 3
001 010 N/A
001 100 N/A
{3}
< ... skip a few iterations ... >
101 001 3
101 010 N/A
101 100 1
{1,3}
< ... etc ... >
答案 1 :(得分:1)
以下代码将比上述算法停止更快。
复杂性明智,您的评估是正确的,因为O(N * 2 ^ N)是输出的大小。
unsigned c;
for (counter = 0; counter < pow_set_size; counter++) {
for (c = counter; c != 0; ) {
if( c & 1 ) {
printf("%c", set[j]);
}
c = c >> 1; // drop lsb
}
printf("\n");
}