Skip to content Skip to footer

007——递归(树的前置知识点)

目录

创建副本

递归

直接调用

间接调用

递归的具体流程又是什么样子的?

递归函数的组成:

递归可以用来解决什么问题?

例子1:求和问题

例子2:斐波那契数列

补充:

说到递归,我们可以简单理解成某个函数直接或间接的调用自身。递,意思是递进;归,意思是回归。而函数调用的本质是创建副本。我们用下面的图解来说明函数的调用为什么是创建副本。

创建副本

在上图的主函数中,调用了fun函数,那么程序在执行到fun(6);语句的时候会创建副本,并执行fun副本中的内容,在执行完fun副本的代码后,便会返回main方法,继续执行下面的代码。

继续说到递归,是某个函数直接或间接的调用自身

递归

直接调用

直接调用的例子如下:

#include

#include

void fun(int a) {

fun(a+10);//直接调用

}

int main() {

fun(4);

}

间接调用

间接调用的例子如下:

#include

#include

void elfun(int b) {

fun(b + 5);//间接调用

}

void fun(int a) {

elfun(a+10);

}

int main() {

fun(4);

}

递归的具体流程又是什么样子的?

我们那下面这个有限递归的代码举例

#include

#include

int x = 0;

void fun(int a) {

printf("%d\n", a);

x++;

while(x<3)

fun(a+10);

printf("***********\n");

}

int main() {

fun(4);

}

运行结果:

该代码的运行流程图是这样的

程序从main函数开始运行,当运行到fun函数时,自动创建副本,代码执行立刻从main函数跳转到副本1,执行副本1函数,执行副本1函数的时候又碰见调用函数fun,接着创建副本2函数并跳转,直到不能跳转为止,在上述代码中程序一共创建了3个副本,当最后一个副本也就是副本3执行完以后,程序运行跳转到上一个副本2,继续执行副本2没有执行完的代码,如此直到第一个副本执行完毕,程序继续执行main函数下面没有执行完的代码。

递归函数的组成:

①递归出口/终止条件/边界条件:停止递归调用的条件,避免死循环/爆内存

②递归体

递归可以用来解决什么问题?

如果一个问题可以分成若干个小问题,并且这些小问题的解决思路和大问题一样

例子1:求和问题

(注意,我们在写递归函数的时候,不要想太多后面它是怎么调用的,要不然有时候容易绕进去,我们只需要搞清楚递归函数的功能(可以看看一次递归函数调用的结果是什么来判断功能是否正确)即可,不要深想)

代码:

#include

#include

int add(int a) {

if (a == 1) {

return 1;

}

int ans;

ans = a + add(a - 1);

return ans;

}

int main() {

int n;

scanf_s("%d", &n);

int sum = 0;

sum = add(n);

printf("1到%d的整数和为%d", n, sum);

}

运行结果:

流程图

例子2:斐波那契数列

#include

#include

int add(int a) {

if (a == 1||a==2) {

return 1;

}

int ans;

ans = add(a - 2) + add(a - 1);

return ans;

}

int main() {

int n;

scanf_s("%d", &n);

int sum = 0;

sum = add(n);

printf("第%d项的斐波那契数列为%d", n, sum);

}

补充:

1.递归只是书写代码的一种格式/方式

2.任何递归代码都可以转化成非递归形式,大部分情况下要借用栈来实现,而一些简单的代码,可以通过循环或者其他形式来实现

3.工程开发中不要用递归,因为递归出口很容易出现问题

4.尾递归,是一种编译层面的优化,是当递归语句在结尾的时候,直接创建一个副本不断覆盖,而不会占用其他空间

Copyright © 2088 世界杯八强_2018年世界杯亚洲区预选赛 - nprny.com All Rights Reserved.
友情链接