zoukankan      html  css  js  c++  java
  • 递归转非递归的编程思想

    1.递归定义的函数在汇编层面很好理解,函数执行过程中对自身的调用实际上是指令的跳转,遇到调用自身的时候指令跳转到函数体的开始位置继续执行,这种跳转不可避免的打断当前函数的执行过程,当跳转部分的指令执行完毕,当前函数的执行过程又被恢复,这一恢复过程就用到了系统的栈,跳转发生之前,函数的相关参数已经保存在了栈中,跳转发生时又会把即将执行的下一条指令位置保存在栈中,也就是说当前函数的执行环境被很好的保存在了栈中。

    2.递归转非递归就是用高级语言模拟这一汇编执行过程,因此这种转换一定是可行的,只是不同的递归模型其转换方式不一样。

    3.拿到一个递归模型,可以看到问题的解答基本上可以分为两部分,一是根据当前执行环境问题不需要进一步分解了,通过若干步骤的运算即可得到结果;二是当前问题的解答有赖于子问题的解答,而且子问题的解出方式和当前问题相同,只是其执行环境会发生变化。我们的模拟也很简单,一个栈元素代表了一个问题的执行环境,每次我们取到栈顶元素进行执行,如果问题被解出那么代表该执行环境的栈顶元素会被弹出,同时根据当前问题的运算结果在其父问题中作用,设置其父问题的执行环境(父问题和其子问题的执行环境总是相邻);如果问题未被解出,那么子问题的执行环境会进栈(父问题被搁置),继续取栈顶元素,模拟问题的解答。需要注意的一点是随着递归的深入一定要有一个终极问题,终极问题的解出会导致父问题的解出(父问题的执行环境弹出),这种连锁反应最终以栈被清空作为结束,也就意味着始祖问题被解出了,模拟过程也就结束了。

    汉诺塔问题为例:

    //递归算法:
    void hanoi(int n,char one,char two,char three)
     {
      void move(char x,char y);
      if(n==1)
         move(one,three);
      else
        {
         hanoi(n-1,one,three,two);
         move(one,three);
         hanoi(n-1,two,one,three);
        }
    }
    //非递归算法:
    //栈的设计
    struct stack{
    int n;
    char x,y,z;
    int yn;//问题是否解出
    int flag;//当前问题处于父问题的哪一个分支上,这个标志会影响当前执行过程对其父问题执行环境的修改
    }st[1024];
    int sttop=-1;
    //非递归函数
    void hanoi()
    {
    //循环体。每次循环取栈顶元素用以模拟一次执行过程。
    while(sttop>-1)
    {
    //第一分支判断问题是否已解出
    if(st[sttop].yn==1)
    {
    if(st[sttop].flag==1)
    {
    movd(st[sttop-2].x,st[sttop-2].z);
    sttop--;
    }
    else if(st[sttop].flag==2)
    {
    st[sttop-1].yn=1;
    sttop--;
    }
    if(st[sttop].flag==0)break;//此问题是始祖问题,计算结束
    }
    //第二分支判断当前问题是否是终极问题(意即此问题的解答变为非递归式解答)
    else if(st[sttop].n==1)
    {
    move(st[sttop].x, st[sttop].z);
    if(st[sttop].flag==1)
    {
    move(st[sttop-2].x, st[sttop-2].z);
    sttop--;
    }
    else if(st[sttop].flag==2)
    {
    st[sttop-1].yn=1;
    sttop--;
    }
    }
    //第三分支当前问题没有解出,将子问题进栈
    else
    {
    st[sttop+1].n=st[sttop].n-1;
    st[sttop+1].x=st[sttop].y;
    st[sttop+1].y=st[sttop].x;
    st[sttop+1].z=st[sttop].z;
    st[sttop+1].yn=0;
    st[sttop+1].flag=2;
    
    st[sttop+2].n=st[sttop].n-1;
    st[sttop+2].x=st[sttop].x;
    st[sttop+2].y=st[sttop].z;
    st[sttop+2].z=st[sttop].y;
    st[sttop+2].yn=0;
    st[sttop+2].flag=1;
    sttop+=2;
    }
    }
    }
    void main()
    {
    //始祖问题进栈
    sttop++;
    st[top].n=7;
    st[top].x='A';
    st[top].y='B';
    st[top].z='C';
    st[top].yn=0;
    st[top].flag=0;
    //开始计算
    hanoi();
    }

    ackerman问题:

    <script>
    function stack(){}
    stack.prototype.m=0;
    stack.prototype.n=0;
    stack.prototype.o=0;
    stack.prototype.LMR=0;
    stack.prototype.yn=0;
    var sttop=-1
    //初始化栈
    var st=new Array(1024);
    for(i=0;i<1024;i++)
    {
    st[i]=new stack();
    }
    //初始环境进栈
    sttop++;
    st[sttop].m=3;
    st[sttop].n=2;
    st[sttop].yn=0;
    st[sttop].LMR=0;
    st[sttop].o=0;
      
    //非递归函数
    function ackm()
    {
    while(sttop>-1){
    if(st[sttop].LMR==0 && st[sttop].yn==1)return st[sttop].o;
    if(st[sttop].yn==1)
    {
    if(st[sttop].LMR==1)
    {
    st[sttop-1].o=st[sttop].o;
    st[sttop-1].yn=1;
    sttop--;
    }
    else if(st[sttop].LMR==2)
    {
    st[sttop-1].n=st[sttop].o;
    sttop--;
    }
    else if(st[sttop].LMR==3)
    {
    st[sttop-1].o=st[sttop].o;
    st[sttop-1].yn=1;
    sttop--;
    }
    }
    else{
    if(st[sttop].m==0)
    {
    st[sttop].o=st[sttop].n+1;
    if(st[sttop].LMR==1)
    {
    st[sttop-1].o=st[sttop].o;
    st[sttop-1].yn=1;
    sttop--;
    }
    else if(st[sttop].LMR==2)
    {
    st[sttop-1].n=st[sttop].o;
    sttop--;
    }
    else if(st[sttop].LMR==3)
    {
    st[sttop-1].o=st[sttop].o;
    st[sttop-1].yn=1;
    sttop--;
    }
      
    }
    else if(st[sttop].n==0)
    {
    st[sttop+1].m=st[sttop].m-1;
    st[sttop+1].n=1;
    st[sttop+1].LMR=1;
    st[sttop+1].yn=0;
    sttop++;
    }
    else
    {
    st[sttop+1].m=st[sttop].m-1;
    st[sttop+1].LMR=3;
    st[sttop+1].yn=0;
      
    st[sttop+2].m=st[sttop].m;
    st[sttop+2].n=st[sttop].n-1;
    st[sttop+2].LMR=2;
    st[sttop+2].yn=0;
      
    sttop+=2;
    }
    }
    }//循环结束
    }//函数结束
    alert(ackm());
    </script>
    相信世界是平的
    谨记四个字“修身养性”
    大江东去浪淘尽英雄,再牛B的人物最后也是一掊土
    向善不是目的,而是抚慰心灵,更多的感受幸福,感谢别人给你行善的机会
    相信老子的话:万物生于有,有生于无,一切的道理都源于一个无法证明的假设
    我是好是坏就自然而然的摆在那里,并不会因为别人的评价而改变什么,我也不需要别人用一张纸来说明我什么,世间最难得的是自由



    支持大额赞助:
  • 相关阅读:
    springMVC初探视图解析器——InternalResourceViewResolver
    从零开始的野路子React/Node(9)Antd + multer实现文件上传
    从零开始的野路子React/Node(8)后端套餐 TS + MySQL + Sequelize + TSOA
    从零开始的野路子React/Node(7)将Swagger(OpenAPI)运用于后端API
    从零开始的野路子React/Node(6)关于模态框的二三事
    从零开始的野路子React/Node(5)近期Hooks使用体会
    从零开始的野路子React/Node(4)后端数据库
    从零开始的野路子React/Node(3)打通前后端
    从零开始的野路子React/Node(2)路由与页面跳转
    从零开始的野路子React/Node(1)React初体验
  • 原文地址:https://www.cnblogs.com/sky-view/p/3246486.html
Copyright © 2011-2022 走看看