利用堆栈消递归练习

某递归定义的函数如下:
f(0)=0
f(1)=1
f(2n)=f(n)
f(2n+1)=f(n)+f(2n-1)
其中,n为非负整数。
以上对应的C语言递归函数的实现如下:

int f(int m)   /* m为非负整数 */
{ 
	if(m==0) return 0;
  	if(m==1) return 1;
  	if(m%2==0) return f(m/2);
  	return f(m/2)+f(m-2);
}

下面探究如何利用堆栈消除递归,以n=3为例:

typedef struct{int n, r1, r2;} ElemTp;  //堆栈元素

r1和r2代表当前项的f(n-2)和f(n/2) (n>1),类似于斐波那契数列的f(n-1)和f(n-2),当r1和r2取-1时代表还未求出,用r =r1 + r2记录求得的值。
首先将(3,-1,-1)压栈,
在这里插入图片描述
因为r1 == -1,由 f(2n+1)=f(n)+f(2n-1),所以取n = 3 - 2 = 1, 将(1,-1,-1)压栈,在这里插入图片描述
此时检查栈顶元素,当n为0或1时,触发递归出口,所以我们规定当n=0时,将r1和r2置为0,此时r1 + r2 = 0;n=1时,将r1和r2分别置为1和0,r1 + r2 = 1,与题意相符合。在这里插入图片描述

现在再检查栈顶元素,发现r1和r2均不为-1,可以进行求值,r = r1 + r2 = 1,然后退栈,此时栈顶元素为(3,-1,-1),r1 = -1,所以将r赋给r1。
在这里插入图片描述
但是r2还未求出,所以继续压栈,根据f(2n+1)=f(n)+f(2n-1),为了求出r2,也就是f(n),我们知道此时需要压栈的元素为(3/2,-1,-1),即(1,-1,-1)。
在这里插入图片描述
继续前面的步骤,
在这里插入图片描述
此时可以求出r2了,
在这里插入图片描述

至此为止r1和r2全部求出,r = r1 +r2 = 2,退栈后变成空栈,此时的r即为所求的值。

代码测试如下:
在这里插入图片描述
两种方法所求的数值一致,并且可以看出利用堆栈消递归可以大大提升程序运行的速度。

实现代码:

#include <iostream>
#include<time.h>
using namespace std;
#define MAX_SIZE 20

typedef struct{int n, r1, r2;} ElemTp;
int stack(int n){
    int r;  //记录 r1 + r2 的值
    ElemTp *s = new ElemTp[MAX_SIZE];
    int top = -1;
    ElemTp a = {n, -1, -1}; 
    s[++top] = a; //(n, -1, -1)压栈

    while(1){
        if(s[top].r1 != -1 && s[top].r2 != -1){
            r = s[top].r1 + s[top].r2;
            --top;
            if(top == -1) break;
            if(s[top].r1 == -1) s[top].r1 = r;  //r1为-1时 将结果赋给r1
            else s[top].r2 = r;
        }
        else{
            if(s[top].n == 0) {s[top].r1 = 0; s[top].r2 = 0;}
            else if(s[top].n == 1) {s[top].r1 = 1; s[top].r2 = 0;}
            else if(s[top].n % 2 == 0){
                s[top].n = s[top].n / 2;  //如果n为大于1的偶数 利用f(2n)=f(n) 将栈顶n除2
            }
            else{
                if(s[top].r1 != -1){
                    a.n = s[top].n / 2;
                    a.r1 = -1;
                    a.r2 = -1;
                }
                else{
                    a.n = s[top].n - 2;
                    a.r1 = -1;
                    a.r2 = -1;
                }
                s[++top] = a;
            }
        }
    }

    delete[] s;
    return r;
}

int f(int m)   /* m为非负整数 */
{ 
    if(m==0) return 0;
    if(m==1) return 1;
    if(m%2==0) return f(m/2);
    return f(m/2)+f(m-2);
}
int main()
{
    clock_t start,finish;
    double totaltime;
    start=clock();

    cout << "非递归算法:" << endl;
    for (int i = 0; i < 30;i++){
        cout << stack(i) << " ";
    }
    finish=clock();
    totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
    cout<<"\n非递归算法的运行时间为"<<totaltime<<"秒!"<<endl;

    start = clock();
    cout << "\n递归算法:" << endl;
    for (int i = 0; i < 30;i++){
        cout << f(i) << " ";
    }
    finish = clock();
    totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
    cout<<"\n递归算法的运行时间为"<<totaltime<<"秒!"<<endl;
} 
  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值