题目
- 原文:
Write a method that returns all subsets of a set. - 译文:
写一个函数返回一个集合中的所有子集。
分析
- 非递归方法:
对于一个长度为n的集合,它的子集共有2^n个,即n转化为二进制后n位选0或者1的组合。这样我们可以通过这些数每位的0、1分布来确定对应子集中是否有所在位的元素出现,具体代码见subset1。 - 递归方法:
依次找集合中除去自己本身的子集,然后再在每个子集中加上自己形成新的子集。以{1,2,3}为例,先找除1以外的子集{ },{2},{3},{2,3},然后再加上包括自己本身在内的子集{1},{1,2},{1,3},{1,2,3},最终共有8个子集,具体代码见subset2。
【这里求除1以外{2,3}的子集也一样,先求除去2以外的子集{ },{3},然后再加上包括2在内的子集{2},{2,3}】
代码
#include<iostream>
#include<vector>
using namespace std;
typedef vector<vector<int> > vvi;
typedef vector<int> vi;
void printsubset(vvi set) {
for(int i = 0; i < set.size(); i++) {
vi sub = set[i];
cout << "{" ;
for(int j = 0; j < sub.size(); j++) {
cout << sub[j] << " ";
}
cout << "}" << endl;
}
}
vvi subset1(int a[], int size) {
int n = 1<<size;
vvi set;
for(int i = 0; i < n; i++) {
int j = i;
int idx = 0;
vi sub;
while(j > 0) {
if(j & 1) {
sub.push_back(a[idx]);
}
j >>= 1;
idx++;
}
set.push_back(sub);
}
return set;
}
//idx代表集合中从第idx位开始的子集
vvi subset2(int a[], int idx, int size) {
vvi set;
//empty
if (idx == size) {
vi sub;
set.push_back(sub);
return set;
}
vvi rset = subset2(a, idx+1, size);
for(int i = 0; i < rset.size(); i++) {
vi sub = rset[i];
set.push_back(sub);
sub.push_back(a[idx]);
set.push_back(sub);
}
return set;
}
int main() {
int a[] = {1, 2, 3};
int n = sizeof(a) / sizeof(int);
vvi sub1 = subset1(a, n);
vvi sub2 = subset2(a, 0, n);
cout << "unrecursion method subset of {1, 2, 3} is: " << endl;
printsubset(sub1);
cout << "recursion method subset of {1, 2, 3} is: " << endl;
printsubset(sub2);
}
结果