注释:打印集合的所有子集

来源:互联网 发布:杭州单片机工程师招聘 编辑:程序博客网 时间:2024/05/16 06:46

已知一个集合,其子集包括空集和本身。怎样将所有的子集打印出来?最简单的O(N^3)算法不难想到,但是太过于朴素,应该还有更巧的方法。

我们已知,一个元素个数为n的集合,其子集个数为2^n个。比如set { 1, 2 },含有两个元素,一共有四个子集,分别为{ },{ 1 },{ 2 },{ 1,2 }。 我们取一个只有两位的bitset,显然这个两位的bitset只有四种组合,00、01、10、11。 假设我们让bitset的每一位对应上面集合中的一个元素,那么集合的每个子集就可以用bitset的一个组合来表示:

{ }       对应  00

{ 1 }    对应  01           

{ 2 }    对应  10

{ 1,2 } 对应  11

在这个对应关系中,bitset的某一位为1,则代表其对应的集合中的元素选入这个子集,为0则代表不选入。

 扩展开,一个具有n个元素的集合,可以用n位的bitset来表示, 将n位的bitset转换为十进制,其范围刚好就是【0,2^n)。上面的特例,bitset转换为十进制后,分别为0、1、2、3。那么,打印一个集合的子集,我们只需要遍历从0到2^n-1的数字,将每个数字看作bitset,只要某位为1则输出该位对应元素。

根据这个思想,形成代码:

//felix:算法思想, {a,b,c,d...) 与二进制的0x11111..每一位互相对应. 形成映射. 相当于一个元素代表一个数。总共会有2^n-1个数,算法是遍历各个数,将一个总和拆成几个基本数的连加.

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include <iostream>  
  2. #include <math.h>  
  3. using namespace std;  
  4.   
  5. void Print(int set[], int n, int k)  
  6. {  
  7.     if (k==0)  
  8.     {  
  9.         cout <<"空集";  
  10.         return;  
  11.     }  
  12.   
  13.     int mask = 1;  
  14.     int index = 0;  
  15.   
  16.     while (index < n)  
  17.     {  
  18.         //mask 1, 2,4,8...,如果k是0x11,则mask=1,2则&出来1,print出来
  19.         if (k&mask)  
  20.         {  
  21.             cout << set[index] << " ";  
  22.         }         
  23.         mask <<= 1;  
  24.         index++;  
  25.     }  
  26. }  
  27.   
  28. void PrintSubSet(int set[], int n)  
  29. {  
  30.     int i;  
  31.   
  32.     for (i=0; i<pow(2,n); i++)  
  33.     {  
  34.         Print(set, n, i);  
  35.         cout << endl;  
  36.     }  
  37. }  
  38.   
  39. void main()  
  40. {  
  41.     int set[4] = {1,2,3,4};  
  42.     PrintSubSet(set, 4);  
  43. }  
输出结果:

0 0
原创粉丝点击