欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

递归和迭代

程序员文章站 2022-04-12 13:15:06
...

c通过运行时堆栈支持递归函数的实现

递归函数就是直接或间接的调用自身的函数。
许多的书上在讲解递归的时候都会用阶乘和斐波那契数列来举例子但是非常不幸的是这两个栗子中,第一个栗子中递归并没有提供任何优越之处,而第二个栗子它的效率之低是肥肠恐怖的!!

我们在之前会学到函数在调用的时候会压栈,调用一次压一次,所以使用递归函数的时候函调用很多很多次堆栈!!这个耗费是肥肠肥肠大的!!那效率是真的很低!!!

我们可以来看一个简单的栗子

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

void Print(int i)
{
    int num = i / 10;//将i/10进入递归函数
    if (num != 0)
    {
        Print(num);//进入函数
    }
    printf("%d  ", i % 10 );
    return;
}
int main()
{
    int i=4267;
    Print(i);
    system("pause");
    return 0;
}

函数一个一个的压栈,因为栈是一种先进先出的规则,所以最后一个压栈的函数最先释放!!所以它会最先打出来!我们可以画个图看一看

递归和迭代
很明显我们可以看到函数的一个压栈的过程,在最后一次函数调用的的过程中num已经变成0,已经不符合if条件所以递归停止,执行后面的语句

printf("%d",i%10);

输出i除10的余数,那么第一个就是4,之后是2······依次打印
但我们在使用递归的时候我们一定要有一个递归的终止条件否则就会出现栈溢出的情况!!这个肥肠重要!!

其实有趣的是,c语言标准中并未说到递归需要堆栈,但是堆栈是非常适合实现递归的所以很多编译器都是用堆栈来实现递归

我们再来看一个栗子,关于我们的斐波那契数列!!我们用这个栗子来说明递归和迭代的一个效率问题
首先我们先用递归来实现斐波那契数列,并且在函数中使用clock函数来计算一下函数的执行的时间,我们就能很明显的比较出它和迭代的效率问题。

我们先来看主函数

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<time.h>
int main()
{
    clock_t clock1 = clock() / CLOCKS_PER_SEC;
    int i;
    printf("请输入数字:(求第几个斐波那契数)");
    scanf("%d", &i);
    size_t add = FeiBo(i);
    clock_t clock2 = clock() / CLOCKS_PER_SEC;
    printf("数字是:");
    printf("%lu\n", add);
    printf("运行时间为(以秒为单位):");
    printf("%lu\n", clock2 - clock1);
    system("pause");
    return 0;
}

在主函数中我是用了一个计时函数(clock),因为这个时钟函数返回的只是一个近似值,所以我就在main函数刚开始的时候调用一次,在函数快结束的时候在调用一次,然后两个值相减就可以比较准确的得到该函数的一个准确的运行时间,方便我们进行比较。
这个clock函数我就不再多说感兴趣的乐意查一下度娘,很简单的

递归

size_t FeiBo(int num)
{
    if (num <= 2)
    {
        return 1;
    }
    else
    {
        return FeiBo(num - 1) + FeiBo(num - 2);
    }
}

运行结果
递归和迭代

迭代

size_t  FeiBo(int num)
{
    size_t i = 0;
    size_t j = 1;
    size_t add = 1;
    while (num > 2)
    {
        num = num - 1;
        i = j;
        j = add;
        add = i + j;
    }
    return add;
}

运行结果
递归和迭代
我们乐意很明显的通过clock函数看出来函数的一个运行时间,一个是13秒,一个是2秒,所以迭代的效率真的是比递归高的真的不是一星半点!!
所以我们在使用递归的时候一定要先问问自己,使用递归的好处是否能低的上使用它的代价,而且必须小心,这个代价可能比你初看上去大很多!!

好啦!!!要是有什么不对的地方!^-^一定要说出来哦!!感谢你!!