在c++中尾递归,普通递归,循环的效率对比

news/2024/7/4 13:03:20
在前面的学习,我们知道普通递归和尾递归的区别,而且在有些语言里是极力提倡尾递归的,如erlang,因为编译器会对其进行优化,不会因为递归次数的增加给函数栈带来巨大的开销。但是c++语言中,g++会对其进行优化吗?现在通过实例分析,看看结论会是什么?

斐波那契数列: 1,1,2,3,5,......
通过c++编程来求 斐波那契数列的第N项的值。试用两种方法,一种是普通递归,另一种是尾递归。
然后统计他们计算第N项的值所花费的时间,来比较两者间的效率。

#include <iostream>
#include <ctime>
using namespace std;

// Normal recusion for fibonacci
unsigned int fib_normal_rec(unsigned int n)
{
    if (n <= 2)
        return 1;
    else
        return fib_normal_rec(n-1) + fib_normal_rec(n-2);
}

// Rail recusion for fibonacci
unsigned int fib_rail_rec(unsigned int n, unsigned int first, unsigned int second)
{
    if (n == 1) return first;
    if (n == 2) return second;
    return fib_rail_rec(n-1, second, second+first);
}
unsigned int fib_rail_rec(unsigned int n)
{
    return fib_rail_rec(n, 1, 1);
}

// No recusion
unsigned int fib_no_rec(unsigned int n)
{
    if (n <= 2)
        return 1;
    unsigned int x=1, y=1, y_tmp=0;
    for (unsigned int i=0; i<n-2; i++)
    {
        y_tmp = y;
        y = x+y;
        x = y_tmp;
    }
    return y;
}

int main()
{
    // fib NUM
    unsigned int fib_num = 10000000000;

    unsigned int t1 = time(NULL);
    //cout <<"Normal fib:" << fib_num << " --> " << fib_normal_rec(fib_num) << endl;
    unsigned int t2 = time(NULL);
    cout << "Normal fib time cost:" << t2-t1 << endl;

    cout << "----------------------------------------------------------" << endl;

    //cout <<"Rail fib:" << fib_num << " --> " << fib_rail_rec(fib_num) << endl;
    unsigned int t3 = time(NULL);
    cout << "Rail fib time cost:" << t3-t2 << endl;

    cout << "---------------------------------------------------------" << endl;

    cout <<"No recusion fib:" << fib_num << " --> " << fib_no_rec(fib_num) << endl;
    unsigned int t4 = time(NULL);
    cout << "No recusion fib time cost:" << t4-t3 << endl;

    return 0;
}

经过反复加注释编译,设置fib_num的大小,最后得出如下测试结果:
非尾递归:当fib_num=45,花费8秒左右得到正确值。
当fib_num设置成50时,运行时间有点长,就没继续等下去了。

尾递归:当fib_num= 100000时,0秒得到正确值。
              当fib_num=1000000时,0秒得到段错误。

循环:   当fib_num=100000000 时,0秒得到正确值。
              当fib_num=1000000000 时,4秒得到正确值。
              当fib_num=10000000000 时,编译会出警告:
recursion.cpp: In function 'int main()':
recursion.cpp:45:  warning:  large integer implicitly truncated to unsigned type

个人得出的结论:
尾递归和循环的执行效率都非常高。但是尾递归的递归层数大到一定程度会出现段错误。
尾递归的函数栈开销比普通递归要小的多,执行效率也要大很多。 但是并不是说尾递归就没有函数栈开销。
正因为尾递归具有函数栈开销,其计算极限要比非递归(循环)小很多。

总之:如果只考虑计算能力, 实现一个功能,能不用递归就别用递归,能用尾递归就别用非尾递归。

http://www.niftyadmin.cn/n/3652970.html

相关文章

C++设计模式——享元模式

C设计模式——享元模式 2014-01-07 分类&#xff1a;C / 设计模式 阅读(634) 评论(12) 前言 无聊的时候&#xff0c;也去QQ游戏大厅玩五子棋或者象棋&#xff1b;作为程序员&#xff0c;看到一个产品&#xff0c;总要去想想它是怎么设计的&#xff0c;怎么完成的&#xff0c;我…

再说c++ static

类外static 1&#xff09;修饰全局变量——限制访问范围为文件内部可见2&#xff09;修饰函数——限制访问范围为文件内部可见3&#xff09;修饰函数内部局部变量——在函数中&#xff0c;只初始化一次&#xff08;即使多次调用&#xff09;&#xff0c;并具有记忆功能4&#x…

从Blog上面去掉那该死的“狗狗订阅”的logo !

只要一写上Blog公告&#xff0c;就会带出来这个难看的“狗狗订阅”的logo&#xff0c;很不爽&#xff0c;为什么要强加于人&#xff01;- -*越看越不爽&#xff0c;杀之&#xff01;用彼之道&#xff0c;还施彼身&#xff01;在公告栏中加入下面的代码&#xff1a;1: <!--//…

杂谈:从今天开始,要认认真真的读书了! 住在十全街的有志青年们!

突然发现自己好像什么都不知道了&#xff01;( 神仙&#xff1f;妖怪&#xff1f;谢谢~~&#xff01;)感觉好怪怪的&#xff0c;还是认真阅读吧&#xff0c;可以给自己一种脚踏实地的感觉&#xff01;而且&#xff0c;因为住在十全街旁边的关系&#xff0c;遇到了太多的有志青年…

[收藏] 版本控制系統使用入門

CVS 入門作者: 臥龍小三 ols3www.tnc.edu.twSubversion Book 的中譯版作者:plasmaballpchome.com.tw

再说c++虚析构函数

关于c类中的虚析构函数。我写这篇博客是为了得出如下3点结论。 1.所有基类的析构函数&#xff0c;都应该声明为虚析构函数&#xff01;这也是c标准所指定的。 2.如果设计一个类&#xff0c;可能会被后来的其他类所继承&#xff0c;我们一定要将它的析构函数声明为虚析构。否则…

修复损坏的VSS数据文件

今天遇到一个问题&#xff0c;使用VSS的时候&#xff0c;突然跳出一个错误&#xff1a;Error reading from file!发现有一个VSS上的目录出现了异常&#xff0c;只要鼠标点击&#xff0c;就跳出这个错误&#xff01;尝试如下动作&#xff1a;- 删除这个分支 ... 失败- 重新命名这…