C++递归函数(入门必读)
如果一个函数在其定义中又调用自身,则称为递归函数,调用自身的过程叫做递归。
递归分为直接递归和间接递归。直接递归是指函数直接调用自身,间接递归则指 A 函数调用了其它函数,而其它的函数中又调用了 A 函数。
递归函数通常由以下两个部分组成:
实际场景中,很多问题适合用递归函数来解决,接下来通过两个实例,带读者体会函数的递归过程。
此时递归开始“展开”,并且每一层递归都会返回其结果:
最后在 main() 函数中,factorial(5) 的结果 120 被赋值给变量 result,然后输出到控制台。
因此,这个递归函数的执行过程首先是“深入”(从 factorial(5) 到 factorial(0)),然后是“展开”(从 factorial(0) 返回到 factorial(5)),在这个过程中逐步完成阶乘的计算。每一层递归都依赖于其下一层的结果,直到达到基本情况,然后逐层返回计算结果。
所谓斐波那契数列,指从 0 和 1 开始,之后每一项都是前两项之和的数列,数列的前几项是
计算斐波那契数列的第 n 个元素,对应的递归函数如下:
fibonacci() 是一个递归函数,它的执行过程是:
至此递归开始“展开”,并且每一层递归都会返回其结果:
虽然递归在解决某些问题方面非常方便,但也是有代价的。每次递归调用都要重新创建一份函数的副本,如果函数中有大量的变量,并且递归层次很多,则内存很快就会被消耗殆尽。因此应用递归时,函数应当尽量简单,而且要尽量减少递归的层次。
递归分为直接递归和间接递归。直接递归是指函数直接调用自身,间接递归则指 A 函数调用了其它函数,而其它的函数中又调用了 A 函数。
递归函数通常由以下两个部分组成:
- 基本情况(Base Case):这是递归的终止条件。没有基本情况,递归函数将无限地调用自己,导致栈溢出。
- 递归情况(Recursive Case):在这里,函数将问题分解成更小的子问题,并自我调用来解决这些子问题。
实际场景中,很多问题适合用递归函数来解决,接下来通过两个实例,带读者体会函数的递归过程。
实例一
计算一个阶乘(n!)是递归的经典应用之一,求 n! 的递归函数如下:#include <iostream> int factorial(int n) { // 基本情况 if (n == 0) { return 1; } // 递归情况 return n * factorial(n - 1); } int main() { int result = factorial(5); // 5的阶乘是120 std::cout << "Factorial of 5 is: " << result << std::endl; return 0; }程序运行后,factorial(5) 函数会被调用,这是一个递归函数,它的执行过程如下:
- factorial(5) 被调用,基本情况 n==0 不成立,所以进入递归情况,计算 5*factorial(4);
- factorial(4) 被调用,基本情况 n==0 不成立,所以进入递归情况,计算 4*factorial(3);
- factorial(3) 被调用,基本情况 n==0 不成立,所以进入递归情况,计算 3*factorial(2);
- factorial(2) 被调用,基本情况 n==0 不成立,所以进入递归情况,计算 2*factorial(1);
- factorial(1) 被调用,基本情况 n==0 不成立,所以进入递归情况,计算 1*factorial(0);
- factorial(0) 被调用,基本情况 n==0 成立,返回 1。
此时递归开始“展开”,并且每一层递归都会返回其结果:
- factorial(1) 计算 1*1=1,所以返回 1;
- factorial(2) 计算 2*1=2,所以返回 2;
- factorial(3) 计算 3*2=6,所以返回 6;
- factorial(4) 计算 4*6=24,所以返回 24;
- factorial(5) 计算 5*24=120,所以返回 120。
最后在 main() 函数中,factorial(5) 的结果 120 被赋值给变量 result,然后输出到控制台。
因此,这个递归函数的执行过程首先是“深入”(从 factorial(5) 到 factorial(0)),然后是“展开”(从 factorial(0) 返回到 factorial(5)),在这个过程中逐步完成阶乘的计算。每一层递归都依赖于其下一层的结果,直到达到基本情况,然后逐层返回计算结果。
实例二
计算斐波那契数列的第 n 个元素是递归的另一个经典例子。所谓斐波那契数列,指从 0 和 1 开始,之后每一项都是前两项之和的数列,数列的前几项是
0 1 1 2 3 5 8 13...
计算斐波那契数列的第 n 个元素,对应的递归函数如下:
#include <iostream> int fibonacci(int n) { // 基本情况 if (n == 0) return 0; if (n == 1) return 1; // 递归情况 return fibonacci(n - 1) + fibonacci(n - 2); } int main() { int result = fibonacci(5); // 第5个Fibonacci数是5 std::cout << "The 5th Fibonacci number is: " << result << std::endl; return 0; }示例程序中,main() 函数调用了 fibonacci(5),也就是计算斐波那契数列的第 5 个元素。
fibonacci() 是一个递归函数,它的执行过程是:
- fibonacci(5) 被调用,基本情况不成立(n!=0且n!=1),所以进入递归情况,需要计算 fibonacci(4)+fibonacci(3);
- fibonacci(4) 被调用,基本情况不成立,所以进入递归情况,需要计算 fibonacci(3)+fibonacci(2);
- fibonacci(3) 被调用,基本情况不成立,所以进入递归情况,需要计算 fibonacci(2)+fibonacci(1);
- fibonacci(2) 被调用,基本情况不成立,所以进入递归情况,需要计算 fibonacci(1)+fibonacci(0)。
- fibonacci(1) 和 fibonacci(0) 被调用,基本情况成立,fibonacci(1)返回 1,fibonacci(0) 返回 0。
至此递归开始“展开”,并且每一层递归都会返回其结果:
- fibonacci(2) 计算 1+0,所以返回 1;
- fibonacci(3) 计算 1+1,所以返回 2;
- fibonacci(4) 计算 2+1,所以返回 3;
- fibonacci(5) 计算 3+2,所以返回 5。
虽然递归在解决某些问题方面非常方便,但也是有代价的。每次递归调用都要重新创建一份函数的副本,如果函数中有大量的变量,并且递归层次很多,则内存很快就会被消耗殆尽。因此应用递归时,函数应当尽量简单,而且要尽量减少递归的层次。