某递归定义的函数如下:
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;
}