4.6 函数的嵌套调用和递归调用

 

4.6 函数的嵌套调用和递归调用

4.6.1 函数的嵌套调用

C++程序中允许函数的嵌套调用。所谓嵌套调用指的是在调用A函数的过程中,可以调用B函数;在调用B函数的过程中,还可以调用C函数。当C函数调用结束后,返回到B函数;当B函数调用结束后,再返回到A函数。前面讲过的例4.2就是函数嵌套调用的一个例子。下面写出该程序执行后的输出结果:

It is in main
It's in fun2.
It's in fun1.
It's in fun3.
It's back in fun1.
It's back in fun2.
It is back in main.

该结果给出函数嵌套调用的具体执行过程。下面以图示进一步说明,如图4-1所示。图中①、②……⑨表示嵌套调用的执行过程。

main() -> fun2() -> fun1() -> fun3()
   ①       ②       ③       ④
   ⑧       ⑦       ⑥       ⑤

嵌套调用是经常使用的。下面举一个函数嵌套调用的例子。

例4.16 编写程序求出下列式子的和:

编程如下:

#include <iostream.h>

const int k = 4;
const int n = 6;

int sum_of_powers(int k, int n);
int powers(int m, int n);

void main() {
    cout << "Sum of " << k << " powers of integers from 1 to " << n << " = ";
    cout << sum_of_powers(k, n) << endl;
}

int sum_of_powers(int k, int n) {
    int sum = 0;
    for (int i = 1; i <= n; i++)
        sum += powers(i, k);
    return sum;
}

int powers(int m, int n) {
    int product = 1;
    for (int i = 1; i <= n; i++)
        product *= m;
    return product;
}

该程序执行后,输出结果如下:

Sum of 4 powers of integers from 1 to 6 = 2275

main() 中调用了 sum_of_powers() 函数,而在 sum_of_powers() 函数中又调用了 powers() 函数,这就是函数调用的嵌套。

4.6.2 函数的递归调用

在C++语言的编程中,允许使用函数的递归调用。所谓函数的递归调用是指在调用一个函数的过程中出现直接或间接调用该函数自身的情况。例如,在调用 f1() 函数的过程中,又调用了 f1() 函数,这称为直接递归调用;而在调用 f1() 函数的过程中,调用了 f2() 函数,又在调用 f2() 函数的过程中调用了 f1() 函数,这称为间接递归调用。

1. 递归调用的特点

在实际问题中,有许多问题可以采用递归调用的方法来解决。下面举一个求正整数5的阶乘问题,即5!。由于5!可以化为5×4!, 4!又可以化为4×3!, 3!可以化为3×2!, 2!可以化为2×1!, 最后1!化为1×0!, 这时,0!等于1是已知的。于是可求出5!为5×4×3×2×1×1等于120。这就是一个既简单又典型的递归调用问题的例子。可见,使用递归调用解决问题的方法如下:

原有的问题能够分解为一个新的问题,而新的问题又用到了原有问题的解法,这就出现了递归。按照这一原则分解下去,每次出现的新问题是原问题简化后的子问题,而最终分解出来的新问题是一个已知解的问题。这便是有限的递归调用。只有有限的递归调用才是有意义的,无限的递归调用在实际中没有意义。

使用递归调用方法编写的程序简洁清晰,可读性强。因此,递归是算法分析与程序设计的一个重要内容。对于能够用递归方法编程的问题,要尽量使用递归。但是,用递归方法编写的程序执行起来在时间和空间的开销上比较大,既要花费较长的计算时间,又要占用较多的内存单元,因为递归的过程中要占用较多的内存单元存放“递推”的中间结果。因此,在速度慢、内存小的机器上难以使用递归,只好用迭代的方法编程。现在,机器的速度高、内存大,一般来说,在支持递归算法的语言中应尽量使用递归。

2. 递归调用的过程

递归调用的过程可分为如下两个阶段。

(1) “递推”阶段

将原问题不断分解为新的子问题,逐渐从未知向已知的方向推测,最终到达已知的条件,即递归结束条件,这时递推阶段结束。

3! = 3 * 2!
2! = 2 * 1!
1! = 1 * 0!
0! = 1 (已知条件)
(2) “回归”阶段

该阶段是从已知的条件出发,按照“递推”的逆过程,逐一求值回归,最后到达递推的开始处,结束回归阶段,完成递归调用。

0! = 1 (已知条件)
1! = 1 * 0! = 1
2! = 2 * 1! = 2
3! = 3 * 2! = 6

下面以求3!为例,写出递归调用的两个阶段,展示全过程,如图4-2所示。

例4.17 编程计算某个正整数的阶乘。假定从键盘上输入一个数存入变量n中,求n!。程序内容如下:

#include <iostream.h>

long int fac(int n);

void main() {
    int n;
    cout << "Input a positive integer: ";
    cin >> n;
    long fa = fac(n);
    cout << n << "!=" << fa << endl;
}

long int fac(int n) {
    long int p;
    if (n == 0)
        p = 1;
    else
        p = n * fac(n - 1);
    return p;
}

执行该程序,显示如下提示:

Input a positive integer: 8
结果为:8! = 40320

其递归过程前面已经分析过了。

例4.18 编程求出Fibonacci数列的第n项。Fibonacci数列定义如下:

假定求出第8项。

编程如下:

#include <iostream.h>

const int N = 8;

long Fibo(int n);

void main() {
    long f = Fibo(N);
    cout << f << endl;
}

long Fibo(int n) {
    if (n == 1)
        return 0;
    else if (n == 2)
        return 1;
    else
        return Fibo(n - 1) + Fibo(n - 2);
}

该程序执行后输出结果如下:

21

请读者自己分析该程序中递归调用的执行过程。

 

 

 

 

 

 

### 关于头歌平台中递归函数嵌套函数 #### 递归函数的理解与实现 在编程领域,递归是一种强大的工具,在特定场景下可以简化代码逻辑并提高效率。当一个函数在其内部调用了自己,则这种行为被称为递归调用[^2]。为了防止无限循环的发生,递归函数必须具备终止条件。 下面展示了一个计算阶乘的简单递归函数实例: ```c #include <stdio.h> int factorial(int n); int main(void){ int num; printf("Enter a positive integer: "); scanf("%d", &num); printf("Factorial of %d is %d\n", num, factorial(num)); } // 定义递归函数来求解n! int factorial(int n){ if (n == 0 || n == 1){ // 终止条件 return 1; } else{ return n * factorial(n - 1); // 自身再次被调用直到满足终止条件为止 } } ``` 这段代码展示了如何通过递归来解决问题,并强调了设置适当退出机制的重要性。 #### 嵌套函数的应用案例 除了递归之外,还可以创建多个相互关联的功能模块——即所谓的“嵌套”。然而需要注意的是,标准C语言并不支持真正的内联定义子函数的方式来进行直接意义上的嵌套声明;但是可以在不同层次上组织这些独立单元之间的关系以达到相似效果[^4]。 这里给出了一组模拟银行账户操作的例子,其中`withdraw()` `deposit()` 是两个辅助性的局部作用域内的功能组件,它们共同服务于外部公开接口`account_operations()`: ```c void account_operations(float balance) { void withdraw(float amount){ if(balance >= amount){ balance -= amount; printf("Withdraw successful! New Balance:%f \n",balance); }else{ printf("Insufficient funds!\n"); } } void deposit(float amount){ balance += amount; printf("Deposit successful! Current Balance:%f \n",balance); } char choice; do{ printf("\nEnter w for Withdraw or d for Deposit:"); scanf(" %c",&choice); float transaction_amount; switch(choice){ case 'w': printf("Amount to withdraw?"); scanf("%f",&transaction_amount); withdraw(transaction_amount); break; case 'd': printf("Amount to deposit?"); scanf("%f",&transaction_amount); deposit(transaction_amount); break; default: printf("Invalid option.\n"); } }while((choice !='q') && ((scanf("Do you want another operation? Press q to quit.")!=EOF))); } ``` 尽管上述结构看起来像是实现了某种形式上的“嵌套”,但实际上每个单独的方法都是全局范围内可见且可以直接访问到的实体。因此这并不是严格意义上按照某些高级抽象语言所理解的那种真正意义上的嵌套特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值