回 帖 发 新 帖 刷新版面

主题:[原创]手工递归一例 for N!

本程序是把求阶乘的递归算法,改成手工执行
[原题]
int fib (int n)
{
        if (n == 1) return 1;
        return n * fib (n - 1);
}


[new]
#include <stdio.h>

struct {
    int ret, n, flag;  /*ret返回域此例无用,flag是递归进度标志*/
} stack [201];              /*函数栈*/

int top = 0;                /*0单元未用,1号位做栈底,top指向栈顶*/

int fib (int n)
{
    int res;

    ++top;
    stack [top].ret  = 0;
    stack [top].n    = n;
    stack [top].flag = 1;    /*初始进栈*/

    while (top > 0) {        /*栈非空循环*/
        if (stack[top].n == 1) {    
            res = 1;
            stack[--top].flag--;
        }  /*同"if (n == 1) return 1;"*/
        else if (stack[top].flag == 1) {
            ++top;
            stack[top].ret = 0;
            stack[top].n   = stack[top-1].n - 1;
            stack[top].flag= 1;
        }  /*同"n * fib (n - 1)"*/
        else if (stack[top].flag == 0) {
            res *= stack[top].n;
            stack[--top].flag--;
        }  /*同return*/
    }
    return res;
}

int main (void)
{
    printf ("%d\n", fib (4)); /*求4!*/
    getch ();
    return 0;
}

通过上一个问题《return i++》理解了return的实际过程。在本例中return分3部分:保存返回值;函数退栈;提示外层函数继续执行(新栈顶flag--)。
关键是flag这个调度标志不好理解。有的函数不只1次递归,像hanoi,在一层里面两次调用自己。那么如何判断何时进行下一个递归呢?就需要flag了,进行完一次调用后flag--,当flag==0时退栈。这是纯粹的对递归过程的模仿,还算不上好的非递归算法,但是可对任何递归进行同样的转化。

更详细的讨论见:euclid.99blog.com

回复列表 (共6个回复)

沙发

看你的题目我很奇怪,手工怎么递归啊?
你这就把递归机械式转换为非递归

板凳

应该是把系统栈用自己定义的STACK代替了,
   给电脑办事,哈哈.

3 楼

此例中flag取1和0表示了栈的进和出。如果是hanoi,则flag取1,2,0分别表示第1次调用、第2次调用、返回。依次类推。

本例只有一个参数,但由于需要记录返回值和flag,相当于要用到3个栈。如果参数很多,那就不好办了。
何况,楼主这个“非递归”算法由于是模拟C语言本来的递归方式,执行效率上反而不如直接用C语言本来的递归。
不过这个例子显示出了递归调用的实际过程,很不错的。

4 楼

网络资源下载中心http://www.nrdc.cn/index.asp大量编程书免费售
不收钱不要邮费 如果本店没有你要的书请到这里给我留言 http://www.nrdc.cn/gbindex.asp 你们开发了东西没有网上空间可放可以到先放我这里来
http;//www.nrd.cn

5 楼

高手

6 楼

应按叫手工模拟递归,除了要锻炼思维,一般不这样做- -0

我来回复

您尚未登录,请登录后再回复。点此登录或注册