• 递归转非递归几个实例


    递归是程序设计中很重要的技巧,简单易于实现;但递归程序效率较之非递归低得多,递归函数要直接或间接的调用自身,系统栈要频繁操作,时间空间消耗很大。在要求高效的很多场合需要将递归程序改写成非递归程序,由于疏于梳理这方面的知识点,感觉对于有些递归结构有些力不从心,于是有意识的学习了一下,感觉好了很多。

    关于递归程序转非递归程序,基本通用方法是用自定义栈结构模拟递归过程,这种方法就是万金油,几乎所有递归都适用,之所以说几乎,主要考虑是暂没有见过用栈解决不了的,但碍于怕自己视野狭窄所以说几乎。如果从系统角度看递归,栈机制模拟能解决所有问题。其次,对于具体问题,可以有其他方法,直接迭代、动态规划什么的,像斐波那契数列就可以用直接迭代写成非递归的;动态规划也是直接迭代的一种,但需要转换思想,提取问题的最优子结构,像数塔问题、归并排序等都属于这类。关于这类,就不说了,这得视具体题目而定,发现问题的结构,寻找状态转移方程。

    一般的还是得用栈模拟,这里主要谈谈栈模拟。以下所有代码重在说明算法,没有考虑爆栈、溢出等涉及程序的鲁棒性因素,还请谅解。

    一、汉诺塔问题

    汉诺塔是根据一个传说形成的一个问题:有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆:
    每次只能移动一个圆盘;
    大盘不能叠在小盘上面。
    提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。问:如何移?最少要移动多少次?(问题描述转自维基百科)

    具体解法思想为先将A杆上面的n-1个借助C杆移到B杆,然后将A杆最低一根直接移到C,再将n-1根借助A杆从B移到C。上面隐含着递归思想将问题逐渐减小最后递推到原问题。

    此时注意栈中元素不是单一的,要保留当前状态,可以用结构体,也可以多维数组,下面给出结构体做法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    #include<IOSTREAM>
    using namespace std;
      
    const int MAXN=10000;
    int m_Move=0;
      
    /**********************************************
    *汉诺塔递归解法
    ***********************************************/
    void recurHanoi(char from,char use,char to,int n)
    {
        if(0==n)
            return ;
        recurHanoi(from,to,use,n-1);
        cout<<N<<"从"<<FROM<<"移到"<<TO<<ENDL; while(top from,use,to,number,id; char myStack[++top]="now;" now.from="'A';now.use='B';now.to='C';now.number=n;now.id=n;" m_Move="0;" top="0;" int now; Node myStack[MAXN]; cout<<?********非递归算法*********?<<endl; { n) notRecurHanoi(int void } cout<<now.id<<?从?<<now.from<<?移到?<<now.to<<endl; ++m_Move; now) print(Node }; to; use; from; id; number; struct *********************************************** *汉诺塔非递归解法 ********************************************** cout<<?**************************?<<endl; cout<<?总共移动?<<m_Move<<?次?<<endl; recurHanoi(&#39;A&#39;,&#39;B&#39;,&#39;C&#39;,n); cout<<?*********递归算法**********?<<endl; recurHanoi(int recurHanoi(use,from,to,n-1);>0)
         {
             if(1==myStack[top].number)
            {
                print(myStack[top]);
                --top;
             }
             else 
             {
                 from=myStack[top].from;use=myStack[top].use;to=myStack[top].to;number=myStack[top].number;id=myStack[top].id;
                 --top;
      
                 now.from=use;now.use=from;now.to=to;now.number=number-1;now.id=id-1;
                 myStack[++top]=now;
      
                 now.from=from;now.use=use;now.to=to;now.number=1;now.id=id;
                 myStack[++top]=now;
      
                 now.from=from;now.use=to;now.to=use;now.number=number-1;now.id=id-1;
                 myStack[++top]=now;     
             }
         }
         cout<<"总共移动"<<M_MOVE<<"次"<<ENDL; int { } cout<<?**************************?<<endl; while(cin n; main()>>n)
        {
            recurHanoi(n);
            notRecurHanoi(n);
        }
        return 0;
    }


    二、组合数

    C(n,m)=C(n-1,m)+C(n-1,m-1) n>m

    C(n,m)=1 n=m或m=0

    此问题的递归形式比较简单,非递归形式得深入理解过程,直接栈模拟,注意进出栈的时机,在此不多说可以看看拙劣的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    #include<IOSTREAM>
    using namespace std;
      
    const int MAXN=100;
      
    int recurCombineCount(int n,int m)
    {
        if(0==m||n==m)return 1;
        else return recurCombineCount(n-1,m)+recurCombineCount(n-1,m-1);
    }
      
    int notRecurCombineCount(int n,int m)
    {
        int stack[MAXN][3];
        int top=0;
        ++top;
        stack[top][0]=n;stack[top][1]=m;stack[top][2]=0;
        do
        {
            if(0==stack[top][2])//计算C(n-1,m)
            {
                ++top;
                stack[top][0]=stack[top-1][0]-1;stack[top][1]=stack[top-1][1];stack[top][2]=0;
                if(stack[top][0]==stack[top][1]||0==stack[top][1])
                    stack[top][2]=1;
            }
            if(top>=2&&stack[top][2]>0)//计算C(n-1,m-1)
            {
                ++top;
                stack[top][0]=stack[top-2][0]-1;stack[top][1]=stack[top-2][1]-1;stack[top][2]=0;
                if(stack[top][0]==stack[top][1]||0==stack[top][1])
                    stack[top][2]=1;
            }
            while(top>=3&&stack[top-1][2]>0&&stack[top][2]>0)//计算C(n,m)
            //注意此处这样有错://if(top>=3&&stack[top-1][2]>0&&stack[top][2]>0)
            {
                stack[top-2][2]=stack[top-1][2]+stack[top][2];
                top-=2;
            }
        }while(top>1);
        return stack[top][2];
    }
      
    int main()
    {
        int n,m;
        while(cin>>n>>m)
        {
            cout<<"************递归算法**************"<<ENDL; } pre < 0; return cout<<?*********************************?<<endl; cout<<?结果为:?<<notRecurCombineCount(n,m)<<endl; cout<<?***********非递归算法*************?<<endl; cout<<?结果为:?<<recurCombineCount(n,m)<<endl;><BR>
       
    <P></P>
    <P>         这几天持续更行中!<BR>
    </P>
    <P>      由于时间有限,疏于测试,如有不足或错误,欢迎斧正!<BR>
    </P>
    <P><BR>
    </P>
    <P><BR>
    </P>
    <P><BR>
    </P>          
  • 相关阅读:
    David Cutler NT之父
    VS2012 RC 编译Qt 4.8.2完整过程
    vm demo加固分析
    IDA dump so
    博客园首次发帖
    WebRTC本地选择codec(web本地模拟)
    Android 摄像头预览悬浮窗,可拖动,可显示在其他app上方
    [译] 清除浮动的新方法
    《学习HTML5游戏编程》译记
    Web中的Tip组件实现
  • 原文地址:https://www.cnblogs.com/firstdream/p/5534220.html
Copyright © 2020-2023  润新知