问题描述:编写c++递归函数,输出n个元素的所有子集,例如三元素集{a,b,c}的子集是、{a}、{b}、{c}、
{a,b},{a,c},{b,c},{a,b,c}。用0/1组成的代码序来表示分别是000,100,010,001,110,101,011,111(0表示
元素在子集中,1表示元素不在子集中)。因此程序只需要输出长度为n的0/1序列即可。
【问题参考:数据结构、算法与应用: C++语言描述 : 原书第2版[M]. 机械工业出版社, 2015. P29. 25题】
问题分析:如果我们要从集合中挑出子集,那么对集合中的每一个元素每次有选或不选两种方案,分别对应0
或是1,所有子集的数量共个。具体的执行步骤是:先对集合中的第n个元素做决策(保留或抛弃),然后
然后再对剩下的n-1个元素做决策,直到决策次数累计有n次(递归终止条件)。具体代码如下
#include "stdafx.h"
#include<iostream>
using namespace std;
//递归函数 输出数组a(长度为len) 前n个元素的所有子集
//a[] 输入字符数组指针
// n 需要输出的前n个元素的所有子集
// len a的长度
void Subset(char a[], int n, int len) {
if (n == 0) { // 递归终止条件
for (int i = 0; i < len; i++) cout << a[i];
cout << endl;
delete[] a; // 这里的a 就是temp
return;
}
for (int j = 0; j <= 1; j++) { //每次需要做两种决策
char *temp = new char[len];
for (int i = 0; i < len; i++) temp[i] = a[i]; //用临时数组来覆盖原来数组
if (j == 0) {
temp[n - 1] = '0';
}else {
temp[n - 1] = '1';
}
Subset(temp, n - 1,len);
}
}
int main()
{
char a[3] = { 'a','b','c'};
Subset(a, 3,3);
char b;
cin >> b; //保留窗体
return 0;
}
程序运行结果如下:
为了更加直观地输出,我们还可以修改成如下的代码
for (int j = 0; j <= 1; j++) {
char *temp = new char[len];
for (int i = 0; i < len; i++) temp[i] = a[i];
if (j == 0) {
temp[n - 1] = '0';
} //去掉else 保留原始字符
Subset(temp, n - 1,len);
}
对应输出结果
不足:程序递归过程中,temp指针只有在递归终点才被删除,因此会有内存泄漏的情况,大家有什么好的想法可以交流下。