排列组合

来源:互联网 发布:怎么激活电脑windows 编辑:程序博客网 时间:2024/04/30 14:28

#include <iostream>
#include <assert.h>
using namespace std;

template<class T> class CPermComb  
{  
private :  
 CPermComb(){} // 必须定义, 且为private.  
 CPermComb(const CPermComb&);            // 不实现. 
 CPermComb& operator=(const CPermComb&); // 不实现.  
 ~CPermComb(){} // 可声明为public, 但这里声明为private没有错, 可被调用.

public :  
 static CPermComb& GetInstance()
 {
  static CPermComb theSingleton;
  return theSingleton;
 }

public :

 //(1)把数组设初值为递增序列,即:1,2,3,4,5,6…
 //(2)设置第一个数为最左端,最后一个数为最右端
 //(3)如果最左端与最右端相同,则输出之,并返回。
 //(4)如果最左端与最右端不同,从左端到右端,逐个遍历
 //(5)在遍历时,遍历到的数与其最左端的数交换
 //(6)把最左端加一作为新的最左端,最右端不变,递归调用自身(2)-(8)。
 //(7)递归调用返回后(即:递归调用的子函数执行(3)后),递归调用前(即:(6)前)的遍历到的数再次与其最左端的数交换,以恢复到递归调用数据交换前的状态。
 //(8)本函数执行完成,返回。
 void Perm_Recursion(T data[], int mid, int max);

 //(1)把数组设初值为递增序列,即:1,2,3,4,5,6…
 //(2)输出数组
 //(3)从后向前查找,看有没有后面的数大于前面的数的情况,若有则停在后一个数的位置i。
 //(4)若没有后面的数大于前面的数的情况,说明已经到了最后一个排列,返回  
 //(5)从后查到i,查找大于p[i - 1]的最小的数,记入j
 //(6)反序排列
 //(7)重复(2)-(6)

 //1. 从当前序列最尾端开始往前寻找两个相邻元素,令前面一个元素为*i,后一个元素为*ii,且满足*i<*ii;
 //2. 再次从当前序列末端开始向前扫描,找出第一个大于*i的元素,令为*j(j可能等于ii),将i,j元素对调;
 //3. 将ii之后(含ii)的所有元素颠倒次序,这样所得的排列即为当前序列的下一个排列。
 void Perm_Unrecursion(T data[], int max);

 //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 CPermComb<T>::Perm_Recursion(T data[], int mid, int max)
{
 assert(data!=NULL,"In Comb_Recursion ,data is NULL/n");

 int curmax;
 if (mid == max)
 {
  //找到一个组合项
  for (curmax = 0; curmax <= max; curmax++)
   cout<<data[curmax] << " ";
  cout<<endl;
 }
 else
 {
  for (curmax=mid; curmax <= max; curmax++)
  {
   swap (data[mid], data[curmax]);
   Perm_Recursion (data, mid+1, max);
   swap (data[mid], data[curmax]);
  }
 }
}

template<class T> void CPermComb<T>::Perm_Unrecursion(T data[], int max)
{
 assert(data!=NULL,"In Comb_Recursion ,data is NULL/n");
 assert(max>0,"In Sort_Counting ,max is <=0/n");

 int i,j;   
 int *tmpdata = new int[max];  
 if(tmpdata==NULL)
 {
  return ;
 }
 memset(tmpdata,0,sizeof(int)*max);
 for(i=0;i<max;i++)
 {
  tmpdata[i]=i;
 }

 while(true)
 {
  for(i=0;i<max;i++)
  {
   cout<<data[tmpdata[i]]<<" ";
  }
  cout<<endl;

  //从后向前查找,看有没有后面的数大于前面的数的情况,若有则停在后一个数的位置i
  for(i=max-1;i>0 && tmpdata[i]<tmpdata[i-1];i--);

  //若没有后面的数大于前面的数的情况,说明已经到了最后一个排列,返回
  if(i==0)
   break;

  //从后查到i,查找大于p[i - 1]的最小的数,记入j
  for(j=max-1;j>i && tmpdata[j]<tmpdata[i-1];j--);

  //交换p[i-1]和p[j]
  swap(tmpdata[i-1], tmpdata[j]);

  ////倒置p[i]到p[n-1]
  for(i=i,j=max-1;i<j;i++,j--)
  {   
   swap(tmpdata[i], tmpdata[j]);
  }
 }    
 delete[] tmpdata;
}

template<class T> void CPermComb<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 CPermComb<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;
}

原创粉丝点击