• 【C++】全排列之非递归算法——字典序法(2)


    递归算法见:http://www.cnblogs.com/caixu/archive/2011/10/31/2229862.html

    题目:1~n的全排列

    思想:(字典序法)初始化数组为1,2,3,...,n作为开端;设法从后续排列中找到大于前次结果但小于其他结果的序列;依此找出这样的序列(后面序列肯定大于前面序列),则最后一个序列肯定是n,...,3,2,1
    步骤:

    • 假设情景:找“*243”该序列的下一个后续序列
    • 从后往前找,找到这样一个数,它后面的数更大,(即找到"*24*",取2作为当前数,下标为i)
    • 在“2”的后面,找到最接近2且比2大的数,这里找到“3”(下标为j)
    • 调换a[i]和a[j]的值
    • 对a[i+1]……a[n-1]进行转置
    • 此时数组a中的数就是所求后续序列
    • 从1,2,3,...,n依此求出后续序列(即重新进行上面步骤),一直找到i=0且a[0]>a[1]则算法结束,全排列已全部给出。

    三思:

    • 怎么保证后面的序列比前面的大?首先开端是序列中最小的,i后面的部分是倒叙排列的,再对调(保证了大于前面序列)后,对i后面的进行逆置,保证了自身是后续排列中最小的,所以小于前面大于后面,依此递增,直到n,...,3,2,1算法结束。
    • 该算法要给一个开端,对于求“142”全排列这种情况,是不是还需要进行先排序得到“124”后再处理?
    • 该算法对调操作频繁,还有转置操作,相比较于递归调用函数,时间更少了,但心里不是滋味。
    • 处理"1223"这种情况又怎样?递归方法不能处理,但这种方法可以处理。
    • 对于字符排序"abc","abb"这两种情况,貌似与数字排序"123","122"一样,反正字符也可以比较大小,所以这两种情况也可以得到解决。

    其他:头文件#include<algorithm>提供字典序法求后续序列的函数为next_permutation(_, _)。

    代码:

    #include <iostream>
    using namespace std;
    const int MaxNum=9;
    int iArr[MaxNum];
    int count;
    inline void printArr(int n)//打印数组,n为元素的总个数
    {
    int i;
    for(i=0;i<n;i++)cout<<iArr[i];
    cout<<endl;
    count++;
    }
    inline void Swap(int i,int j)//调换iArr[i]与iArr[j]的值
    {
    int temp=iArr[i];
    iArr[i]=iArr[j];
    iArr[j]=temp;
    }
    void Transpose(int k,int m)//把数组下标为k~m的数转置
    {
    int i,j;
    for(i=k,j=m;j>i;i++,j--)Swap(i,j);
    }
    int FullArray2(const int n)//对1~n进行全排列
    {
    if(1==n){cout<<"1"<<endl;count++;return 1;}//特殊情况n=1
    int i,j;
    while(1){
    printArr(n);
    for(i=n-2;i>=0;i--){//要求n>=2
    if(iArr[i]<iArr[i+1])break;//先求i
    if(0==i)return 1;//函数出口:当i=0且iArr[0]>iArr[1]时,函数结束
    }
    for(j=n-1;j>i;j--){
    if(iArr[i]<iArr[j])break;//后求j
    }
    Swap(i,j);//调换iArr[i]与iArr[j]的值
    Transpose(i+1,n-1);//把i后面的数转置
    }
    }
    void main()
    {
    int i,n;
    while(1){
    system("cls");
    count=0;//测试新用例时,count重新置0
    cout<<"请输入n(最大为9):";
    cin>>n;
    if(n>MaxNum || n<1){cout<<"Error: n的值在设定值范围之外"<<endl;break;}
    for(i=0;i<n;i++)iArr[i]=i+1;//由于FullArray2上一次调用完,不会把调换的元素调整回来,故每次调用FullArray2前都要对数组进行重新初始化,即这条语句不能放在while循环外。
    FullArray2(n);
    cout<<"1~"<<n<<"的全排列的个数:"<<count<<endl;
    system("pause");
    }
    }

    参考:http://plutoblog.iteye.com/blog/976216

    http://bbs.byr.cn/pc/pccon.php?id=1041&nid=72574

    【递增进位制数法】、【递减进位制数法】、【邻位对换法】、【格雷码序之类的方法】都待考。

  • 相关阅读:
    docker使用
    window版docker安装及配置
    mysql命令
    xshell
    git 命令
    分页器原理
    PCL-Kinfu编译手册
    cmake-add_definitions
    cmake-include_directories
    cmake-source_group
  • 原文地址:https://www.cnblogs.com/caixu/p/2230497.html
Copyright © 2020-2023  润新知