求集合的所有子集
2012-03-28 19:52
176 查看
现有一个包含N个元素的集合S,求集合S的所有子集?
例如:集合S包含三个元素{a, b, c},则它的所有子集为:{ }(空集), {a}, {b}, {c}, {a, b}, {a, c}, {b, c} 和{a, b, c}。
这里先用位操作的思路来求解,具体方法:用2进制Bit位来标记集合中的某个元素是否被选中,1代表选中,0代表未选中。例如集合{a, b, c}的所有子集可如下表示:
{}(空集) 0 0 0
{a} 0 0 1
{b} 0 1 0
{c} 1 0 0
{a, b} 0 1 1
{a, c} 1 0 1
{b, c} 1 1 0
{a, b, c} 1 1 1
从上面的分析中也可以看出一个包含N个元素的集合S有2^N个子集,非常容易想到的方法就是遍历0~2^N-1的所有整数,并转化为二进制,按以上思路输出所有子集。但这里我们参照《求比正整数N大的最小正整数M,且M与N的二进制表示中有相同数目的1》的方法来求解集合S的所有子集。具体实现如下:
这里再提供一种递归的思路来解决问题,会借助一个全局变量来记录所有选中的元素,具体代码如下:
例如:集合S包含三个元素{a, b, c},则它的所有子集为:{ }(空集), {a}, {b}, {c}, {a, b}, {a, c}, {b, c} 和{a, b, c}。
这里先用位操作的思路来求解,具体方法:用2进制Bit位来标记集合中的某个元素是否被选中,1代表选中,0代表未选中。例如集合{a, b, c}的所有子集可如下表示:
{}(空集) 0 0 0
{a} 0 0 1
{b} 0 1 0
{c} 1 0 0
{a, b} 0 1 1
{a, c} 1 0 1
{b, c} 1 1 0
{a, b, c} 1 1 1
从上面的分析中也可以看出一个包含N个元素的集合S有2^N个子集,非常容易想到的方法就是遍历0~2^N-1的所有整数,并转化为二进制,按以上思路输出所有子集。但这里我们参照《求比正整数N大的最小正整数M,且M与N的二进制表示中有相同数目的1》的方法来求解集合S的所有子集。具体实现如下:
#include <iostream> using namespace std; const int OK = 0; const int ERROR = 1; int getNextN(int n) { int temp1 = n & (-n); int temp2 = n + temp1; int ret = temp2 | ((n ^ temp2) / temp1) >> 2; return ret; } template<class T> void output(T set[], int k, int n) { int index = 0; bool flag = false; cout << "{"; while (n) { if (n % 2 == 1) { if (flag) { cout << ", "; } cout << set[k + index]; flag = true; } n /= 2; index++; } cout << "}" << endl; } //生成集合set[k:m]的所有子集 template<class T> int SubSet(T set[], int k, int m) { if (k < 0 || m < 0 || k > m) { return ERROR; } output(set, k, 0); //空集作特殊处理 int num = m - k + 1; for (int i = 1; i <= num; i++) //从集合set[k:m]中选择i个元素 { int beginIdx = (1 << i) - 1; int endIdx = (1 << num) - (1 << (num - i)); for (int j = beginIdx; j <= endIdx;) { output(set, k, j); j = getNextN(j); } } return OK; } int main(int argc, char *argv[]) { char str[10]; cout << "请输入一个字符数组:"; cin >> str; SubSet(str, 0, strlen(str) - 1); system("PAUSE"); return EXIT_SUCCESS; }
这里再提供一种递归的思路来解决问题,会借助一个全局变量来记录所有选中的元素,具体代码如下:
#include <iostream> using namespace std; int g_used[10] = {0}; template<class T> void Output(T set[]) { bool flag = false; cout << "{"; for (int i = 0; i < 10; i++) { if (g_used[i] == 1) { if (flag) { cout << ", "; } cout << set[i]; flag = true; } } cout << "}" << endl; } //生成集合set[k:m]的所有子集 template<class T> void SubSet(T set[], int k, int m) { if (k > m) { return Output(set); } g_used[k] = 0; //未选中 SubSet(set, k + 1, m); g_used[k] = 1; //选中 SubSet(set, k + 1, m); } int main(int argc, char *argv[]) { char str[10]; cout << "请输入一个字符数组:"; cin >> str; SubSet(str, 0, strlen(str) - 1); system("PAUSE"); return EXIT_SUCCESS; }
相关文章推荐
- 产生一个集合的所有子集
- 算法作业:求一个集合中所有子集元素之和
- 9.9递归和动态规划(四)——返回某集合的所有子集
- 求集合的所有子集(续)
- 输出集合的所有子集(幂集)-C语言
- 利用自然数的标准分解证明可数集合的所有有限子集形成的集合是可数集
- 注释:打印集合的所有子集
- 枚举一个集合的所有子集
- 返回某整数集合的所有子集
- 利用自然数的标准分解证明可数集合的所有有限子集形成的集合是可数集
- 程序员面试金典(动态规划):返回某集合的所有子集(java解法)
- 两种方法寻找一个集合的所有子集
- 求集合的所有子集(java实现)
- 求集合中的所有子集
- 求集合所有子集问题
- 求一个集合的所有子集
- 求一个集合的所有子集
- C语言递归求解集合的所有子集
- 一个集合的所有子集的Java代码实现
- 输入一个集合,输出这个集合的所有子集