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

在前面的学习,我们知道普通递归和尾递归的区别,而且在有些语言里是极力提倡尾递归的,如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

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

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

你可能感兴趣的:(效率,循环,尾递归)