递归优化——尾递归果然给力
这几天又翻出一本《C++大学教程·第五版》看,看着看着就看到Fibonacci数列,很简单就写了个递归想算一下,代码非常朴素,但是没想到居然这么慢,加上个GetTickCount()函数一看,算到第40个数就耗费了大约31秒的时间,实在让人汗颜,在网上搜索了一把,发现了本文http://blog.zhaojie.me/2009/03/tail-recursion-and-continuation.html,大为惊叹,原来递归也是可以优化的,稍微修改了一下变为尾递归再计算,居然只需31毫秒,1000倍啊!
上面那个链接老赵写的很好,我就不浪费口水了,给出朴素的代码和优化后的代码充一下字数吧。
朴素的递归计算Fibonacci数列:
#include <iostream>
#include <ctime>
#include <windows.h>
using std::cout;
using std::endl;
unsigned fibonacci(int n)
{
if (n < 2)
{
return n;
}
else
{
return fibonacci(n-1)+fibonacci(n-2);
}
}
int main()
{
DWORD tt;
int i;
tt = GetTickCount();
for (i = 1; i < 41; i++)
{
cout << i << "\t" << fibonacci(i) << endl;
}
cout << "It takes you " << GetTickCount() - tt << "ms to work it out." << endl;
return 0;
}
转变为尾递归之后的代码:
#include <iostream>
#include <ctime>
#include <windows.h>
using std::cout;
using std::endl;
unsigned fibonacci(int n,unsigned acc1,unsigned acc2)
{
if (n < 2)
{
return acc1;
}
else
{
return fibonacci(n-1,acc2,acc1+acc2);
}
}
int main()
{
DWORD tt;
int i;
tt = GetTickCount();
for (i = 1; i < 41; i++)
{
cout << i << "\t" << fibonacci(i,1,1) << endl;
}
cout << "It takes you " << GetTickCount() - tt << "ms to work it out." << endl;
return 0;
}
fibonacci(n-1,acc2,acc1+acc2)真是神来之笔,原本朴素的递归产生的栈的层次像二叉树一样,以指数级增长,但是现在栈的层次却像是数组,变成线性增长了,实在是奇妙,总结起来也很简单,原本栈是先扩展开,然后边收拢边计算结果,现在却变成在调用自身的同时通过参数来计算。