写在最前面
一位粉丝私信交流,回想起了当初的我C语言一题写一下午的,而且很多概念糊糊的不清楚。借助这次机会,整理了相关 C 语言中最常见而关键的疑惑,并对概念进行解答。
本篇博客的前身:
【新手解答1】深入探索 C 语言:变量名、形参 + 主调函数、被调函数 + 类和对象 + 源文件(.c 文件)、头文件(.h 文件)+ 库
【新手解答2】深入探索 C 语言:变量名、变量 + 函数声明 vs 函数定义 + main的声明 + 头文件和源文件的关系
【新手解答3】深入探索 C 语言:头文件提供必要的接口、源文件保持实现细节的私有性 + 进一步学习的方向 + 如何快速编写程序并最终能制作小游戏
【新手解答4】深入探索 C 语言:全局变量声明、全局函数声明 + 宏定义
【新手解答5】深入探索 C 语言:宏中的文本、标识符和字符串 + 递归运算、条件语句、循环 + switch-case
与多项条件和枚举的差别
【新手解答6】深入探索 C 语言:算法流程图(条件判断、循环)+ 字符常量 + switch的具体用法 + 关于namespace
+ import vs include
【新手解答7】深入探索 C 语言:代码缩进 + 变量作用域、静态变量 + 变量名和函数名重名
如有不对的地方欢迎指出!好久没接触C了hh
这章重点:
循环(loop)和递归(recursion)是两种不同的控制流机制。递归是通过函数自我调用
来实现重复的,而循环则是在同一函数体内重复执行代码块
。
问题:探索递归与循环在C语言中的应用
int f(int n) { int res; if (n == 1) res = 1; else { } res = f(n-1) + 3; return res; }
上面代码是斐波那奇数列的,假如设置一个条件为n小于五,N大于五则减三,并再输入n判断大小,那么这个时候很明显是要用到循环的了,那么,这里的循环和函数又是什么关系呢?并且循环所包括的if会不会和else样重新输入?
解析
在深入探讨这个问题之前,让我们先理解一下代码片段所示的功能。
这段代码看似意在实现一个类似于斐波那契数列的递归函数,但实际上并未完全实现。
让我们先完善这个函数,然后讨论如何将循环逻辑集成到其中。
现有代码分析
int f(int n) { int res; if (n == 1) res = 1; else { // 递归调用缺失逻辑 } res = f(n-1) + 3; // 这行代码会在所有情况下执行,包括n==1 return res; }
这段代码中存在一些问题:
- 递归基准条件:
if (n == 1) res = 1;
是递归的基准条件,但接下来的res = f(n-1) + 3;
也会在n == 1
的情况下执行,这可能导致无限递归。 - 递归逻辑:代码中
else
部分的逻辑尚未定义,这是实现递归的关键部分。
整合循环
现在,我们想要在 n
小于5时按一定规则执行,而 n
大于5时则按另一规则执行,并在此过程中使用循环。
这里的主要疑问是:如何将循环与递归函数结合
。循环和递归都是实现重复操作的方法,但它们在结构和用途上有所不同:
- 递归 是一种通过函数调用自身来重复执行代码的方法。
- 循环 通过结构(如
for
或while
循环)在一定条件下重复执行代码块。
要在此函数中整合循环,我们可以根据 n
的值在递归调用之前执行不同的循环逻辑。例如,如果 n
小于5,我们可以在递归调用之前执行一个循环;如果 n
大于5,我们则执行另一个循环。
示例代码修改
以下是根据描述修改后的函数示例:
int f(int n) { if (n == 1) { return 1; } else { if (n < 5) { // 在这里执行某种循环逻辑 } else { // n大于5时的不同循环逻辑 } return f(n-1) + 3; } }
在这个示例中,if (n < 5)
和 else
部分是根据 n
的值执行不同的循环。这些循环可以是任何我们所需要的逻辑,例如增加、减少或者修改变量值。
注意事项
- 避免无限递归:确保递归函数有明确的退出条件,否则可能导致堆栈溢出。
- 递归与循环的选择:在某些情况下,使用循环而非递归可能更为高效,尤其是在深度递归可能导致性能问题的场景。
结论
结合循环和递归可以实现复杂的逻辑,但需要谨慎设计以避免常见的陷阱,如无限递归。根据具体的应用场景选择适当的方法是关键。
延伸:递归和循环的退出条件设置
对了,假如重新输入n- 3,如n=6,则n- 3=3,需要再次输入,那么,这按照赋值运算符来说就是,N=n- 3,但这样明显是不对的,又该怎样呢?
解析
我的理解是,想要在函数中实现一种逻辑,其中当 n
大于 5 时,将 n
减少 3,并对更新后的 n
值再次进行某种操作。
为了实现这个功能,在编程中通常可以通过递归或循环来实现。
让我们根据这个需求来设计这个函数。
使用递归
递归方法是一种函数在执行过程中调用自身的技术。在这个例子中,如果 n
大于 5,我们可以在函数中减少 n
的值,并再次调用这个函数。这样,每次调用都会检查 n
的值,并根据条件适当地更新 n
。
示例代码如下:
int f(int n) { if (n <= 5) { // 当n小于等于5时的处理逻辑 return n; // 例如,直接返回n } else { // 当n大于5时,减少3并递归调用 return f(n - 3); } }
这个函数会递归地减少 n
的值,直到 n
小于或等于 5 为止。每次递归都会减少 n
的值。
使用循环
另一种方法是使用循环。在循环中,我们可以持续减少 n
的值,直到满足某个条件(例如,n
小于或等于 5)。
示例代码如下:
int f(int n) { while (n > 5) { n -= 3; } // 当n小于等于5时的处理逻辑 return n; // 例如,直接返回n }
在这个例子中,当 n
大于 5 时,循环会持续执行,并逐渐减少 n
的值。一旦 n
小于或等于 5,循环结束,函数返回当前的 n
值。
选择适合的方法
- 如果问题的性质更适合于逐步递减并递归地处理每个步骤,那么选择递归方法。
- 如果问题更倾向于简单地减少一个值直到达到某个阈值,那么使用循环可能更为简洁和高效。
在这两种情况下,都需要确保存在适当的退出条件,以防止无限递归或无限循环的发生。