• 排列问题的递归算法和非递归算法


    参考:算法设计与分析 郑宗汉

    原理:

    简单地说:第一个数与后面的依次交换!

    E.g:E = (a , b , c),则 prem(E)= a.perm(b,c)+ b.perm(a,c)+ c.perm(a,b)

    然后a.perm(b,c)= ab.perm(c)+ ac.perm(b)= abc + acb.依次递归进行

    排列生成的代码:

    #include<iostream>
    using namespace std;
    /*
    数组a[],元素个数n,后面需要排列的元素个数k
    */
    void perm(int a[],int k,int n)
    {
        int i;
        if(k==1) 
        {
            for(i=0;i<n;i++) //已构成一个排列,输出它
                cout<<a[i];
            cout<<endl;
        }
        else
        {
            for(i=n-k;i<n;i++) //生成后续k个元素的一系列排列
            {
                swap(a[n-k],a[i]); //元素互换
                perm(a,k-1,n);      //生成后续k-1个元素的一系列排列
                swap(a[n-k],a[i]); //恢复元素原来的位置
            }
        }
    }
    int main()
    {
        int a[]={1,2,3,4,5};
        perm(a,3,5);
    }

    输出:

    12345
    12354
    12435
    12453
    12543
    12534
    请按任意键继续. . .

    如果不恢复原来的位置会输出什么?

    12345
    12354
    12534
    12543
    12345
    12354

    算法复杂时间度

    k=1. 输出n个元素

    k=n;对perm(a,k-1,n)执行n次调研,

    f(1)=n;

    f(n)=nf(n-1);

    f(n)=nn!.

     c++ swap函数:

    template <class T> void swap ( T& a, T& b )
    {
    T c(a); a=b; b=c;
    }

     上面的解法从后面开始,我们可以从前面开始,比较好理解:

    #include<iostream>
    using namespace std;
    //b表示开始的元素,e表示最后的元素
    void perm_aux(int a[],int b,int e) { int i; if(b==e) { for(i=0;i<=e;i++) cout<<a[i]; cout<<endl; } else { for(i=b;i<=e;i++) { swap(a[b],a[i]); perm_aux(a,b+1,e); swap(a[i],a[b]); } } } void perm(int a[],int n) { perm_aux(a,0,n-1); } void perm(int a[],int b,int e) { perm_aux(a,b,e); } int main() { int a[]={1,2,3,4,5}; perm(a,2,4); //生成345的全排列 }

    我们重载了perm函数,使其可以直接使用

    perm(a,sizeof(a)/sizeof(int))或采用上面的形式。

    上面的递归属于指数递归:

    指数递归定义:

    An exponential recursive function is one that, if you were to draw out a representation of all the function calls, would have an exponential number of calls in relation to the size of the data set (exponential meaning if there were n elements, there would be O(an) function calls where a is a positive number).

    上面的代码存在的问题:两个相同的数也进行了交换如果是

    {1,2,2}输出:

    122
    122
    212
    221
    221
    212
    请按任意键继续. . .

    明显不符合要求。

    改进后代码:

    bool isSwap(int a[],int b,int e)
    {
        for(int i=b;i<e;i++)
        {
            if(a[i]==a[e])
                return false;
        }
        return true;
    }
    void perm_aux(int a[],int b,int e)
    {
        int i;
        if(b==e)
        {
            for(i=0;i<=e;i++)
                cout<<a[i];
            cout<<endl;
        }
        else
        {
            for(i=b;i<=e;i++)
            {
               if(isSwap(a,b,i))
               {
                swap(a[b],a[i]);
                perm_aux(a,b+1,e);
                swap(a[i],a[b]);
               }
            }
        }
    }

    122。输出;

    122
    212
    221
    请按任意键继续. . .

    i=0 isSwap(0,0) true,perm_aux(a,1,2). 返回false.

    i=1 isSwap(a,0,1) 可以交换

    i=2 isSwap(a,0,2)  

    for(int i=b;i<e;i++)
        {
            if(a[i]==a[e])
                return false;
        }
        return true;

    在2前面a[1]=a[2],返回false。不可以交换

    重要的是IsSwap函数。

     更多算法:

    http://www.cnblogs.com/bakari/archive/2012/08/02/2620826.html

    http://www.cppblog.com/goal00001111/archive/2009/01/20/72378.html

    http://hi.baidu.com/tjuer/item/4e2701cae435dc3c44941685

  • 相关阅读:
    C#方法Extra
    C#方法
    C#类型与变量
    归并排序算法
    2020 CiGA Game Jam活动总结
    插入排序算法
    游戏开发随笔
    2019厦门大学信息学院人工智能/智能科学与技术系夏令营(非计算机系)
    基于Dlib、OpenCV开发人脸识别程序的开发建议
    CCF CSP 201703
  • 原文地址:https://www.cnblogs.com/youxin/p/3257785.html
Copyright © 2020-2023  润新知