c语言第三课:函数递归

目录

1.【递归:从概念到实践】

1.1  什么是递归?

1.2  递归的原理

1.3  递归的经典例子:阶乘

1.3.1  代码分析

1.4  递归溢出的问题


1.【递归:从概念到实践】

1.1  什么是递归?

  1. 在数学和计算机科学中,递归是指一个函数不断调用自身的过程。递归函数通常通过不断将问题分解为更小的、类似的子问题来解决复杂的任务。
  2. 递归的核心思想是将大问题分解为小问题,直到达到基本情况(递归的终止条件),然后逐层返回结果。

1.2  递归的原理

递归函数通常包括两部分:基本情况和递归情况。基本情况是指递归过程中能够立即得到解答的情况,它是递归的终止条件。递归情况则是指在函数内部调用自身来解决规模更小的子问题。

递归函数的执行过程可以用以下步骤来描述:

  1. 检查是否满足基本情况,如果是,则返回特定的值。
  2. 如果不满足基本情况,将问题分解为更小的子问题,然后调用自身来解决这些子问题。
  3. 逐层返回结果,最终得到整个问题的解答。

1.3  递归的经典例子:阶乘

让我们以计算阶乘为例来演示递归的实际应用。阶乘表示从1到n的所有正整数的乘积,通常用符号n!表示。阶乘的递归定义如下:

  • 当n为1时,n! = 1
  • 当n大于1时,n! = n * (n-1)!

下面是用C语言实现阶乘递归的代码:

#include <stdio.h>

int dg(int n) 
{
    if (n == 1) 
    {
        return 1; // 基本情况
    } 
    else 
    {
        return n * dg(n - 1); // 递归情况
    }
}

int main() 
{
    int n = 5;
    int x = dg(n);
    printf("%d的阶乘是%d\n", n, x);
    return 0;
}

在这个例子中,factorial 函数通过递归调用自身来计算阶乘。当n为1时,函数返回1作为基本情况;当n大于1时,函数调用自身来计算(n-1)的阶乘,并将结果乘以n,最终得到n的阶乘。

1.3.1  代码分析

让我们来分析一下这个函数的执行过程:

  1. 当调用 dg(n) 时,函数首先检查基本情况:如果 n 等于 0 或 1,那么它的阶乘就是 1,于是函数直接返回 1。

  2. 如果 n 不等于 0 或 1,那么函数执行 return n * dg(n-1)。这里就是递归的关键:函数调用了自身,并且传入了一个比原来小的数(n-1)。

  3. 这个过程会一直持续下去,直到 n 等于 0 或 1,然后逐层返回结果,直到得到最终的阶乘值。


让我们以一个具体的例子来说明这个过程。假设我们要计算dg(5)

  1. dg(5) 返回 5 * dg(4)
  2. dg(4) 返回 4 * dg(3)
  3. dg(3) 返回 3 * dg(2)
  4. dg (2)返回 2 * dg(1)
  5. dg(1) 返回 1

然后逐层返回结果:

  1. dg 返回 2 * 1 = 2
  2. dg 返回 3 * 2 = 6
  3. dg 返回 4 * 6 = 24
  4. dg 返回 5 * 24 = 120

因此,递归的执行过程更像是一种"等待"的过程,每次函数调用都需要等待它所调用的函数返回结果,然后才能继续执行。只有当递归调用到达基本情况时,才会开始逐层返回结果,最终得到整个问题的解答 

1.4  递归溢出的问题

当处理递归函数时,我们通常会面临函数递归溢出的问题。递归溢出是指在使用递归算法时,递归的层次过深,导致系统栈空间不足,从而抛出栈溢出异常。下面我将使用 JavaScript 代码来说明递归函数的问题以及解决方法。

#include <stdio.h>

// 递归函数计算斐波那契数列
int dh(int n) 
{
    if (n <= 1) 
    {  // 终止条件
        return n;
    } 
    else 
    {
        return dh(n - 1) + dh(n - 2);  // 递归调用
    }
}

// 调用递归函数
int main() 
{
    int result = dh(40);  // 尝试计算斐波那契数列第40项
    printf("%d\n", result);
    return 0;
}

在上述代码中,我们定义了一个计算斐波那契数列的递归函数 dh。然而,如果我们尝试计算较大项数的斐波那契数列,比如 dh(40),就会遇到栈溢出的问题。

为了解决这个问题,我们可以使用尾递归优化或者循环来改写递归函数,以减少系统栈的压力。

下面是使用尾递归优化的计算斐波那契数列的函数:

#include <stdio.h>

// 尾递归优化的计算斐波那契数列函数
int dh_tail(int n, int a, int b) 
{
    if (n == 0) 
    {  // 终止条件
        return a;
    }
    return dh_tail(n - 1, b, a + b);  // 尾递归调用
}

// 调用尾递归优化的函数
int main() 
{
    int result = dh_tail(40, 0, 1);  // 计算斐波那契数列第40项
    printf("%d\n", result);
    return 0;
}

另外,我们也可以使用循环的方式来计算斐波那契数列,从而避免递归调用的深度过深:

#include <stdio.h>

// 循环计算斐波那契数列的函数
int dh_iterative(int n) {
    int a = 0, b = 1, temp;
    if (n == 0) {
        return a;
    }
    for (int i = 2; i <= n; i++) {
        temp = a + b;
        a = b;
        b = temp;
    }
    return b;
}

// 调用循环函数
int main() {
    int result = dh_iterative(40);  // 计算斐波那契数列第40项
    printf("%d\n", result);
    return 0;
}

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值