文章目录
前言
递归是那种一眼看上去很简单,但是一仔细想就越想越乱的问题
一. 递归三要素
1.1 递归的定义
形参,返回值,返回值的含义
1.2 递归表达式
如何把大问题拆解成小问题
1.3 递归出口
在什么情况下return
1.4 讨论
为什么递归出口要放到递归表达式前面????
A:解答这个问题需要捋清递归问题的执行流程。递归函数的结构一般是:
递归出口
操作x
递归表达式
操作y
(1)第一次进入递归函数,会执行递归调用之前的所有操作,以及递归调用本身。
(2)往后都是如此,递归调用之前的所有操作,以及递归调用本身。不执行递归调用之后的操作
(3)执行到最后一次递归调用,进入递归函数,递归出口条件满足,return.不会执行递归出口之后的递归调用。
(3)执行最后一次递归调用之后的操作,然后return
(4)执行上一次递归调用之后的操作,然后return
(5)以此类推
总结起来就是,在满足递归出口条件之前,不会执行递归调用之后的操作。
要将递归函数分成递归调用之前和之后
假设出口放到递归调用之后,那么无论如何都执行不到递归调用之后的操作,也就永远遇不到出口,最终导致递归深度溢出
二. 递归的分类
2.1 单向递归
2.1.1 打印整数
从没想过打印整数也能改成递归。但仔细一想,递归和迭代本就不是泾渭分明,递归都可以改成迭代,而反之则不然
这确实是两种思想啊
(1)递归定义。一个函数必然有一个功能,递归和迭代都是一样的,打印从1-n的整数。传入的参数都是n,什么都不需要返回,在函数中完成相应的打印操作即可
(2)递归表达式。按照一贯思路,对递归函数的定义进行拆解,要打印1-n的整数,可以先打印n,再打印1-n-1的整数,以此类推。也就是将1-n-1的打印任务交给其他函数去完成
(3)递归出口。如果…,就不再执行后面的操作了,也就不会再进行递归调用了。迭代里边有循环结束的条件,递归是类似的,递归出口条件满足之后,也就不会再执行之后的递归调用了
def digui(n):
if n < 1:
return
digui(n - 1)
print(n)
三. 内存
至少java和python遵循上述的内存结构,C++就把某些引用数据类型放到栈空间,这有隐患
3.1 函数调用栈
第一个进入“圆筒”的是main函数,每发生一次新的函数调用,就会有一个新函数进入“圆筒”,正在执行的就是最上面的函数,一个函数执行完毕,就会被拿出来
四. 参数传递
这三种我都实践过,C++是最原始的那种,三种都有,还保留了越写越乱的指针
4.1 值传递
相当于创建一个新的变量,把值拷贝一份,修改新的变量原来的变量不会受到影响。这已经非常熟悉了。有时候为了避免这一点,还得要用一个引用进行包装
java和c++都you基本数据类型,python不一样,但是python的不可变类型的传递可以被视作值传递,像列表的传递就是一种引用传递