【C语言深度剖析】深入理解C语言中函数的递归算法

简介: 【C语言深度剖析】深入理解C语言中函数的递归算法

文章目录

定义

递归: 一个函数在它的函数体内调用它自身,这种调用过程称为递归,这种函数称为递归函数

在递归调用中,主调函数又同时是被调函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层

难点

运行递归函数将无休止地调用其自身,这当然是不正确的!

为了防止递归调用无终止的进行,就必须在函数内有终止递归的条件判断语句,满足某种条件后就不再作递归调用,然后逐层返回!!!

这也是递归不易理解的一个难点!

举例说明

我这里通过举例来说明这个递归是如何使用的吧

例题一

接受一个整型值(无符号),按照顺序打印它的每一位。

例如:

输入:1234,输出 1 2 3 4

代码如下:

#include <stdio.h>
void Print(unsigned int n)
{
    if (n > 9)
    {
        Print(n / 10);
    }
    printf("%d ", n % 10);
}
int main()
{
    unsigned int num = 0;
    scanf("%u", &num);
    Print(num);
    return 0;
}

分析:

我这里画了一个图,配合下面的解析看,如图:(红色表示递,绿色表示归)

image.png

当我们走到主函数里面的时候,我们先输入一个数字:123,那么num = 123

然后就调用我们的Print(num)函数,此时我们就叫做递出去

图A:

  • 所以此时的图A当中的n = 123,然后判断if语句:123 > 9为真,进入内部,然后调用Print(n / 10)函数
  • 这次调用的Print函数就走到了图B,此时我们传进去的就是:123 / 10 的结果,也就是12

图B:

  • 所以图B中的n = 12,然后判断if语句:12 > 9为真,进入内部,那么又要调用Print(n / 10)函数
  • 这次调用的Print的函数就走到了图C,此时我们传进去的就是:12 / 10 的结果,也就是1

图C:

  • 所以图C中的n = 1,然后判断if语句:1 > 9为假,所以直接执行print语句,1 % 10 = 1,那么就会在屏幕上打印1和空格

图B:

  • 此时我们图C中的函数已经调用完了,那么就要回归到图B函数中,执行图B中的printf语句,而图B中的n = 12
    那么12 % 10 = 2,然后打印2和空格

图A:

  • 此时我们又要从图B回归到图A,执行图A中的printf语句,而图A中的n = 123,那么123 % 10 = 3,然后打印3和空格

主函数:

  • 图A函数执行完以后,又要回归到我们的主函数Print(num),此时我们的函数调用任务已经结束了,屏幕打印输出:1 2 3

这就是递归的过程,递出去,归回来,

例题二

我们再来做一个题检验一下!

有5个学生在一起

问第五个学生多少岁?他说他比第四个学生大2岁;

问第四个学生多少岁?他说比第三个学生大2岁;

问第三个学生多少岁?他说比第二个学生大2岁;

问第二个学生多少岁?他说比第一个学生大2岁;

最后问第一个学生,他说是10岁。

请问第5个学生多少岁?

这里的话我们用递归的思想来做这道题

思考

age(5) = age(4) + 2;

age(4) = age(3) + 2;

age(3) = age(2) + 2;

age(2) = age(1) + 2;

age(1) = 10;

用数学公式表达如下:

    age(n)= 10; (n = 1)
    age(n)= age(n-1) + 2;(n > 1)

可以看到,当n >1时,求第n个学生的年龄的公式是相同的

因此可以用一个函数表示上述关系。如图表示求第5个学生年龄的过程image.png

显然,这是一个递归问题

由图所示,求解可分为两个阶段:

第1阶段是 回溯,即将第n学生的年龄表示为第(n-1)个学生的函数,而第(n-1)个学生的年龄仍然还不知道,还要回溯到第(n-2)个学生的年龄……直到第一个学生的年龄。此时age(1)已知,不必再向前推了。

然后开始第二阶段,采用递归方法,从第一个学生的已知年龄推算出第二个学生的年龄(12岁),从第二个学生的年龄推算出第三个学生的年龄(14岁)……一直推算出第5个学生的年龄(18岁)为止。

也就是说,一个递归的问题可以分为回溯和递归两个阶段。要经历若干步才能求出最后的值。显而易见,如果要求递归过程不是无限制进行下去,必须具有一个结束递归过程的条件。

本例中,age(1)=10,就是使递归结束的条件。

代码如下:

#include <stdio.h>
int age(int n)
{
    int c = 0;
    if (n == 1)
    {
        c = 10;
    }
    else
    {
        c = age(n - 1) + 2;
    }
    return c;
}
int main()
{
    int stu = 0;
    stu = age(5);
    printf("第五个学生的年龄为: %d\n", stu);
    return 0;
}

总结

一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法

它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解

递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量

递归的主要思考方式在于: 把大事化小


相关文章
|
2月前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
73 23
|
4月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
109 1
|
5天前
|
人工智能 Java 程序员
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
11 1
一文彻底搞清楚C语言的函数
|
2月前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
78 15
|
2月前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
65 24
|
2月前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
75 16
|
2月前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
42 3
|
2月前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
24 2
|
2月前
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
56 1
|
3月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
101 10

热门文章

最新文章