输出集合{1,2,...,n}的所有子集
来源:互联网 发布:什么软件可以涂鸦照片 编辑:程序博客网 时间:2024/05/24 15:41
输出集合{1,2,…,n}的所有子集
注意,集合{1,2,…n}与任何一个含有n个元素的集合是同构的,所有下面的算法适用于求解任何的集合。
基于完全二叉树的深度优先搜索
以集合{1,2,3}为例:
基于bit pattern
对于一个含有n个元素的集合,可以用一个n位的2进制数来表这个集合,第i为1表示第i个元素在表示的集合中,否则不在 。
[对一个数加上1,体现在bit位上的效果就是从低位向高位寻找,找到第一个0 bit位之后,将这个bit位置1,并将他后面的所有低位置0]
[顺便提一下,对一个数减1,体现在bit位上的效果就是从低位向高位寻找,找到第一个1 bit位之后,将这个bit位置0,并将他后面的所有低位都置1—对应的题可参见【编程之美】]
按字典顺序排序
排在集合
{X,j,i} (X表示小于j的元素构成的某个集合)后面的集合为:
1. i< n 时,为{X,j,i,i+1}
2. i= n 时,为{X,j+1} , 特别地,当X为空集,且j+1=n时,所有子集已经确定。
#include<iostream>#include<vector>#include<algorithm>#include<iterator>using namespace std;void subsetHelper(vector<int> temp, int const& n, vector<vector<int>>& result){ if (n == 0){ sort(temp.begin(),temp.end()); result.push_back(temp); return; } subsetHelper(temp, n - 1, result);//不选n temp.push_back(n);//选n subsetHelper(temp, n - 1, result);}/*这是一个求集合{1,2...n}的所有子集的函数,基于一棵完全二叉树*/void subset_v1(int const& n, vector<vector<int>>& result){ vector<int> temp; subsetHelper(temp, n, result);}/*这是一个求集合{1,2...n}的所有子集的函数,基于bitpattern*/void subset_v2(int const &n, vector<vector<int>>& result){ vector<int> *temp; vector<char> BitArray(n);//n 个字符(初始化为0)---> n bit result.push_back(* new vector<int>()); int i, j; while (true){ for (i = 0; i < n &&BitArray[i] == 1; BitArray[i] = 0, i++)//找到最右边的一个零 ; if (i == n) break;//全部为1,所有情况都已经收录到result里了。 BitArray[i] = 1; temp = new vector<int>(); for (j = 0; j < n; j++){ if (BitArray[j]) temp->push_back(j + 1); } result.push_back(*temp); }}/*这是一个求集合{1,2...n}的所有子集的函数,按字典顺序排序。*/void subset_v3(int const &n, vector<vector<int>>& result){ int pos(0); vector<int> *temp; result.push_back(* new vector<int>());//初始添加一个没有大小的集合,也就是空集 temp = new vector<int>(); temp->push_back(1); pos++; while (true) { result.push_back(*temp);//将上一轮循环得到的结果保存 if ((*temp)[pos - 1] < n){//最右边的元素不是最大值n时,继续往右走 temp = new vector<int>(*temp); temp->push_back((*temp)[pos - 1] + 1); pos++; } else if (pos == 1){//{n}的情况,退出循环 break; } else{//{...i,n}的情况,这个集合的下一个集合因该是{...i+1} pos--; //新开辟大小为pos的vector vector<int> *temp1 = new vector<int>(pos); copy(temp->begin(), temp->begin() + pos, temp1->begin()); //上面一行不能写成 "copy(temp->begin(), temp->begin() + (pos - 1), temp1->begin());"。 //容器的定义是[begin, end),end不是容器中的一个元素。 temp = temp1; (*temp)[pos - 1]++;//将第pos个元素加1。 } }}int main(){ vector<vector<int>> result; int n; cout << "输入集合上限n:" << endl; cin >> n; subset_v1(n, result); cout <<"subset_v1:------------------------基于完全二叉树深度搜索" << endl; for (int i(0); i < result.size(); i++){ cout << "{"; copy(result[i].begin(), result[i].end(), ostream_iterator<int>(cout)); cout << "}"; cout << endl; } result.clear(); subset_v2(n, result); cout << "subset_v2::------------------------基于集合的bitpattern表示" << endl; for (int i(0); i < result.size(); i++){ cout << "{"; copy(result[i].begin(), result[i].end(), ostream_iterator<int>(cout)); cout << "}"; cout << endl; } result.clear(); subset_v3(n, result); cout << "subset_v3::------------------------按字典排序之后" << endl; for (int i(0); i < result.size(); i++){ cout << "{"; copy(result[i].begin(), result[i].end(), ostream_iterator<int>(cout)); cout << "}"; cout << endl; } system("pause"); return 0;}
按Gray码排序
什么是Gray 码? n bit 的Gray 码是一连串共有
2n 个元素的数列,每一个元素都有n bit ,
而且任何相邻的两个元素之间只有1bit 的值不同。例如, 3 个bit 的Gray 码:
000 001 011 010 110 111 101 100
是一组Gray 码,任何相邻两个元素都只有1 bit 值不同。但是, Gray 码却并不是惟一的。把n=4 的一种Gray 码写出来:
0000 0001 0011 0010 0110 0111 0101 0100
1100 1101 1111 1110 1010 1011 1001 1000
发现从第1个数到第2个数是第1位变了,第2个数到第3个数是第2位变了,把所有位置写下来有:
1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1
可以归纳出:
第奇数个的数(0000算第0 个)永远是改变上一个值最右边一位而得来的,可能是0 变成1,也可能是1 变成0; 总之,变成了相反的值。
再看第偶数个的数(0011 ,0110,0101 , 1100, 1111 , 1010, 1001) ,它们是从改变上一个值的2,3 ,2,4,2,3,2 这几位而来;再仔细看看,它们的右边邻位(1,2,1,3,1,2,1 )值都是1,而且是从右边算过来的第一个1 。因此:
第偶数个的数(0000不计)的值是从改变上一个值中右边算来第一个1 的左边邻位而得来。
code:
/*这个函数用来按Gray码排序集合的所有子集, 所谓Gray是指相邻的两个码之间只有一位不同*/void subset_v4(int const &n, vector<vector<int>>& result){ vector<int> *temp; //BitArray[0]--对应{xxxxxxx}中的最右边一位。 vector<char> BitArray(n);//n 个字符(初始化为0)---> n bit result.push_back(*new vector<int>());//空集是任何集合的子集---对应{000...0}。 temp = new vector<int>(); temp->push_back(1); result.push_back(*temp); //将1放入结果中---对应{000...01} for (int i(1); i < n; i++){ BitArray[i] = 0; } BitArray[0] = 1;//初始BitArray ={1000...0}---对应{000...01} int even = 1;//表示正在处理的是Gray码序列中的第偶数个数{类似数组,1对应0,2对应1...}。 int i; while (true){ i = 0; for (; i < n&&BitArray[i] == 0; i++);//找到右边第一个1。 if (i == n-1)break; if (even) { BitArray[i + 1] = 1 - BitArray[i + 1]; even = 1 - even; } else{ BitArray[0] = 1 - BitArray[0]; even = 1 - even; } temp = new vector<int>(); for (int j(1); j <= n; j++){ if (BitArray[j - 1]) temp->push_back(j); } result.push_back(*temp); }}
0 0
- 输出集合{1,2,...,n}的所有子集
- 求集合{1, 2, ..., n}的所有子集
- 输出集合的所有子集
- 求集合{1,2,...,n}的长度小于M(M<=n)的所有子集
- 求集合{1,2,...,n}的长度等于M(M<n)的所有子集
- 列出{1,2,,,,n}的所有子集
- 输出集合所有子集的算法
- 输出一个集合所有的子集合
- 输出一个集合的所有子集
- 输出集合所有子集的算法
- 输出一个集合的所有子集合
- 算法篇:输出集合的所有子集
- 输出一个集合的所有子集
- 输入一个集合,输出这个集合的所有子集
- 生成集合[n]的所有k-子集MATLAB代码
- 使用递归函数,输出n个元素的所有子集
- 使用递归函数,输出n个元素的所有子集
- 有一个集合A,它又n个元素,请用回溯法输出它所有的子集。
- PHP中获取某个网页或文件内容的方法
- 2013山东省第四届ACM省赛 Contest Print Server
- 算法分析之——计数排序
- 乘积最大
- Intel VTune 访存分析
- 输出集合{1,2,...,n}的所有子集
- Android 中用HttpClient进行网络数据加载时,得到String乱码的问题
- 订单系统、库存系统、优惠券系统如何保证数据一致性
- 括号序列
- Windows程序设计基础(1)
- Java学习笔记
- 异常捕获机制中的return
- 网线的直连线与交叉线之间的区别
- java与java web学习浅谈