给定集的功率集

时间:2014-09-22 12:13:16

标签: c algorithm

给定一组我想显示其所有子集(其功率集)。我找到了这段代码:

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)是否有更好的方法?

2 个答案:

答案 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");
}