#include <iostream>
#include <math.h>
#include <assert.h>
using namespace std;
template<class T> class CElementSubset
{
private :
CElementSubset(){} // 必须定义, 且为private.
CElementSubset(const CElementSubset&); // 不实现.
CElementSubset& operator=(const CElementSubset&); // 不实现.
~CElementSubset(){} // 可声明为public, 但这里声明为private没有错, 可被调用.
public :
static CElementSubset& GetInstance()
{
static CElementSubset theSingleton;
return theSingleton;
}
public :
//非递归求元素子集可以考虑使用二进制方法求解,但是当长度超出32比特位时,处理起来就有问题了
void ES_Unrecursion(T data[], int n);
//另一种非递归方法可以借助非递归组合方法进行求解,这种不受32比特位长度的限制
void ES_Unrecursion1(T data[], int n);
//求元素子集最直接的办法就是依次找1~N元素的子集即可
void ES_Recursion(T data[], int n);
//mask是标示位数组,c代表从第c个元素开 始寻找子集里面的元素
void ES_Recursion1(T data[], bool mask[], int n, int c);
void ES_Recursion2(T data[],int n,int nLow,int nHigh);
private :
//1. 首先从n个数中选取编号最大的数,然后在剩下的n-1个数里面选取m-1个数,直到从n-(m-1)个数中选取1个数为止。
//2. 从n个数中选取编号次小的一个数,继续执行1步,直到当前可选编号最大的数为m。
// 求从数组a[1..n]中任选m个元素的所有组合。
// a[1..n]表示候选集,n为候选集大小,n>=m>0。
// b[1..M]用来存储当前组合中的元素(这里存储的是元素下标),
// 常量M表示满足条件的一个组合中元素的个数,M=m,这两个参数仅用来输出结果。
void Comb_Recursion( T a[], int n, int m, T b[], const int M );
// 求从数组a[1..n]中任选m个元素的所有组合。
// a[1..n]表示候选集,m表示一个组合的元素个数。
// 返回所有排列的总数。
void Comb_Unrecursion(T data[],int n,int m);
};
template<class T> void CElementSubset<T>::ES_Unrecursion(T data[], int n)
{
assert(data!=NULL,"In ES_Unrecursion ,data is NULL/n");
assert(n>0,"In ES_Unrecursion ,len is <=0/n");
if (n <= 0 || data == NULL)
{
return;
}
int value = (int)pow((double)2,(double)n) - 1;
int curpos=0;
int curvalue = 0;
do
{
curpos=0;
curvalue = value;
while(curvalue>0)
{
if (curvalue % 2 != 0)
{
cout<<data[curpos]<< " ";
}
curvalue = curvalue/2;
curpos++;
}
cout<<endl;
} while (--value > 0);
}
template<class T> void CElementSubset<T>::ES_Unrecursion1(T data[], int n)
{
assert(data!=NULL,"In ES_Unrecursion1 ,data is NULL/n");
assert(n>0,"In ES_Unrecursion1 ,len is <=0/n");
for (int k=1;k<=n;k++)
{
T* data1 = new T[k];
memset(data1,0,sizeof(T)*k);
Comb_Unrecursion(data, n, k);
delete[] data1;
}
}
template<class T> void CElementSubset<T>::ES_Recursion(T data[], int n)
{
assert(data!=NULL,"In ES_Recursion ,data is NULL/n");
assert(n>0,"In ES_Recursion ,len is <=0/n");
for (int k=1;k<=n;k++)
{
T* data1 = new T[k];
memset(data1,0,sizeof(T)*k);
Comb_Recursion (data, n,k,data1,k);
delete[] data1;
}
}
template<class T> void CElementSubset<T>::ES_Recursion1(T data[], bool mask[], int n, int c)
{
assert(data!=NULL,"In ES_Recursion1 ,data is NULL/n");
assert(mask!=NULL,"In ES_Recursion1 ,mask is NULL/n");
assert(n>0,"In ES_Recursion1 ,len is <=0/n");
if (c == n)
{
//如果是从最后一个元素开始寻找自己里面的元素,那就直接将mask为1的元素加到自己里面来。这个是递归结束条件
for (int i = 0; i < n; i++)
if (mask[i])
cout<<data[i]<<" ";
cout<<endl;
}
else
{
//子集分割为求含有第C个元素的子集和没有含第C个元素的子集, 这样反复递归
//将第c个元素的标示位置为1,即第c个元素是子集里面的一个元素(1)
mask[c] = true;
//从第c+1个元素开始寻找子集中的元素
ES_Recursion1 (data, mask, n, c + 1);
//将第c个元素的标示位置为0,即第c个元素不是子集里面的一个元素(2)
mask[c] = false;
//从第c+1个元素开始寻找子集中的元素
ES_Recursion1 (data, mask, n, c + 1);
}
}
template<class T> void CElementSubset<T>::ES_Recursion2(T data[],int n,int nLow,int nHigh)
{
assert(data!=NULL,"In ES_Recursion2 ,data is NULL/n");
assert(n>0,"In ES_Recursion2 ,len is <=0/n");
if(nLow < nHigh && nHigh <= n)
{
for(int i = nLow;i < nHigh;i++)
{
cout <<data[i]<<" ";
}
cout <<endl;
}
if(nHigh == n)
{
ES_Recursion2(data,n,nLow+1,nLow+2);
}
else if(nHigh <= n)
{
ES_Recursion2(data,n,nLow,nHigh+1);
}
}
template<class T> void CElementSubset<T>::Comb_Recursion( T a[], int n, int m, T b[], const int M )
{
assert(a!=NULL,"In Comb_Recursion ,a is NULL/n");
assert(b!=NULL,"In Comb_Recursion ,b is NULL/n");
for(int i=n; i>=m; i--)
{
b[m-1] = i - 1;
if (m > 1)
{
Comb_Recursion(a,i-1,m-1,b,M);
}
else
{
for(int j=M-1; j>=0; j--)
cout << a[b[j]] << " ";
cout << endl;
}
}
}
template<class T> void CElementSubset<T>::Comb_Unrecursion(T data[],int n,int m)
{
assert(data!=NULL,"In Comb_Recursion ,data is NULL/n");
assert(n>0,"In ES_Recursion2 ,len is <=0/n");
assert(m>0,"In ES_Recursion2 ,m is <=0/n");
int index,i;
int* tmpdata = new int[m];
if(tmpdata==NULL)
return ;
memset(tmpdata,0,sizeof(int)*m);
index=0;
tmpdata[index]=0;
while(true)
{
if(tmpdata[index]>=n)
{
//以index-1前面个数组成的组合已经全部走完,需要回退一步,
if(index==0)
{
//各种情况取完了,不能再回退了
break;
}
index--;//回退一步
tmpdata[index]++;//替换元素
}
else if(index==m-1)
{
//找到一个组合了
for (int i=0;i<m;i++)
{
cout<<data[tmpdata[i]]<<" ";
}
cout<<endl;
tmpdata[index]++; //替换元素
}
else
{
//加入一个元素
index++;
tmpdata[index]=tmpdata[index-1]+1;
}
}
delete[] tmpdata;
}