排列组合算法(非递归)

来源:互联网 发布:路由器关闭了所有网络 编辑:程序博客网 时间:2024/05/21 11:17
/************************
 * 排列组合算法
 * 非递归方式
 *
 * 编译器:borland c++
 * 时间:2013-10-10
 * 笔名:Jungle
 *
 *
 * 说明:排列的核心算法来源:
 * http://blog.csdn.net/hackbuteer1/article/details/6657435
 * http://plutoblog.iteye.com/blog/976216
 * http://blog.csdn.net/aipb2008/article/details/2227490
 *
 * 组合算法是自己设计的。
 *
 ***********************/


#include <iostream>
using namespace std;


// 在[All]中选[Opt]的全排列
// 思路:先组合再全排列
#define swap(type,a,b) {type temb=a; a=b; b=temb;}
void Permutation(int *,int);
void Permutation_Combination(int All,int Opt); // 排列


// 在[All]中选[Opt]的所有组合
void Combination(int All,int Opt); // 组合




void main(void)
{
    Permutation_Combination(6,3);
    Combination(8,4);


    cin.get();
    cout<<"F i n i s h !"<<endl;
}


/*
  非递归全排列算法


  这个算法是C++ STL算法next_permutation的思想。


*/


void Permutation(int *a,int length)
{
    int i,j;
    while(1)
    {
        // 打印输出
        for(i=0; i<length; ++i)
            { cout<<a[i]<<" "; }
        cout<<endl;
        cin.get();


        // 后->前,找到【Ai<A(i+1)】的[i]位置
        for(i=length-2; i>=0; --i)
        {
            if(a[i]<a[i+1])
                { break; }
            else if(i==0) // 找不到升序的数据,全排列结束。
                { return; }
        }
        // 后->前,找到比【Aj>Ai】的[j]位置
        for(j=length-1; j>i; --j)
        {
            if(a[j]>a[i])
                { break; }
        }
        // 交换位置i,j的值
        swap(int,a[i],a[j]);
        // 【(i+1)至结束位置】的所有数据逆序
        i++;
        j=length-1;
        for(; i<j; ++i,--j)
        {
            swap(int,a[i],a[j]);
        }
    }
}




void Permutation_Combination(int All,int Opt)
{
    if(All<Opt || Opt<2) { return; }


    // 组合算法
    int flag=0;
    int *com=new int[Opt+1];


    com[0]=1;
    while(1)
    {
        if(com[flag] > (All-Opt+flag+1))
        {
            if(flag == 0)
            {
                delete []com;
                return;
            }
            com[--flag]++;
        }
        else
        {
            if(flag == (Opt-1))
            {
                // 得到一个组合,是升序排列
                // 进而求出该组合的全排列
                int *per=new int[Opt];
                for(int i=0;i<Opt;i++)
                {
                    per[i]=com[i];
                }
                Permutation(per,Opt);
                cout<<"------------"<<endl;
                delete []per;
            }
            com[flag+1]=com[flag++]+1;
            if(flag == Opt) { com[--flag]++; }
        }
    }
}




/*----------------------------------------------------------
  非递归组合算法


  说明:
  以5选3为例,共10种组合,如下:
  ...  百--十--个 位的数据
  ...  1,  2,  3,
  ...  1,  2,  4,
  ...  1,  2,  5,
  ...  1,  3,  4,
  ...  1,  3,  5,
  ...  1,  4,  5,
  ...  2,  3,  4,
  ...  2,  3,  5,
  ...  2,  4,  5,
  ...  3,  4,  5,


  1.可以看出百位的数据<=3,十位的数据<=4,个位的数据<=5,
    即每个位置上的值都有各自的范围。
  2.组合中的数据总是升序的,因为数据都是由高位推出低位。
  3.采用进位的思路,低位数据超出范围,高1位进位。
  4.定义:个位称为最低位。
 ---------------------------------------------------------*/


void Combination(int All,int Opt)
{
    int i;
    int flag=0; // 当前位置标识
    int *com=new int[Opt+1]; // 要求数组长度>=(Opt+1)


    com[0]=1; // 初始化最高位
    while(1)
    {
        // 当前位置的值溢出
        if(com[flag] > (All-Opt+flag+1))
        {
            if(flag == 0)
            {
                delete []com;
                return; // 最高位溢出则结束。
            }
            // 低位溢出,高1位进位。
            com[--flag]++;
        }
        // 当前位置的值没有溢出
        else
        {
            if(flag == (Opt-1))
            {
                // 位置标识指向个位时,得到一个组合,输出
                for(i=0;i<Opt;i++)
                    { cout<<com[i]<<' '; }
                cout<<endl;
                cin.get();
            }
            // 低位=高位+1
            com[flag+1]=com[flag++]+1;
            // 个位的低1位称为最最低位
            // 位置标识指向最最低位时,个位上的数进位
            if(flag == Opt) { com[--flag]++; }
        }
    }
}