/*
设计递归函数,用来输出n个元素的所有子集(2^n个)。
考题:由一个集合的所有子集构成的集合称为该集合的________。(幂集)
思路:设n个元素(a1,...an)构成的集合为Sn,如果已经有了Sn中前n-1个元素(a1,a2,...an_1,其集合记作Sn_1)的子集An_1,则
所求结果为①An_1并上以下集合:将an放入An_1的各个元素(也是集合)中构成新的元素(也是集合)所组成的集合②。
如
Sn={b,c,a},
则①An_1={{},{b},{c},{b,c}},
an=a,
② ={{a},{a,b},{a,c},{a,b,c}}
则An = ①∪② ={{},{b},{c},{b,c},{a},{a,b},{a,c},{a,b,c}}即为最终结果。
可以用递归或非递归两种方式求解。这里按要求用递归来求解。
难点:如何构建输出(结果集)且能在函数间传递?-> vector和全局变量result
*/
#include <iostream>
#include <vector>
using std::cout;
using std::cin;
using std::endl;
using std::vector;
typedef vector<char> subset; //存放{a,b}这样的子集
vector<subset> result = {subset() }; //上述子集的集合,形如{{},{a,b},{a}},用于保存每一步处理的结果。最后就是总的结果。
void solve(vector<char>& src)
{
if (src.size())
{
//删除来源中的末尾字符
char c = src.back(); //保存末尾元素,后面会用到
src.pop_back();
solve(src); //删除末尾元素后的集合再次求解更小规模的问题(减少一个字符):
//至此,得到了前n-1次处理的结果
vector<subset> temp = result; //前n-1个元素构成的所有子集的集合,拷贝一份
for (auto it = temp.begin(); it != temp.end(); it++)
{
(*it).push_back(c); //修改temp的元素,往每个子集中都添加一个c,
}
//循环完成后,temp中的每个元素都是含有c的字符的子集
//然后,将temp加到result后面,构成新的result。
result.insert(result.end(), temp.begin(), temp.end());
}
else { // src中没有字符了
return;
}
}
//打印字符集中字符的一种组合(一个字符子集,如{'a','b','c'})
void print_combination(const subset& s)
{
cout << "{";
for (auto it = s.begin(); it != s.end(); it++)
cout << *it ;
cout << "}";
}
//打印所有子集,需调用print_combination函数
void print_subsets(const vector<subset>& r)
{
int i = 0;
cout << "{"<<endl;
for (auto it = r.begin(); it != r.end(); it++)
{
cout << ++i << ":";
print_combination(*it);
cout << "\n";
}
cout << "}"<<endl;
}
//主函数
int main()
{
char s[] = { 'A','B','C'}; //初始字符集:可用动态数组,从键盘输入值
subset original(s,s+sizeof(s)/sizeof(char)); //初始字符集
solve(original); //求解
print_subsets(result); //打印结果
return 0;
}
运行结果: