1. 递归
1.1
1.2 递归形式
1.2.1 无返回值
- 样式1
def st(n):
if n <= 0:
return
#print (n)
st(n-1)
print (n)
print (st(5))
#----------
1
2
3
4
5
None
- 样式2
def st(n):
if n <= 0:
return
print (n)
st(n-1)
#print (n)
print (st(5))
#-------
5
4
3
2
1
None
- 样式3
def st(n):
if n <= 0:
return
print (n)
st(n-1)
print (n)
print (st(5))
# -----------
5
4
3
2
1
1
2
3
4
5
None
可以看出,递归的过程是调用st(n-1)
方法,在这个方法之前的处理都是在向右的方向中,也就是在向更深层调用的过程
在这个方法之后的处理都是在向左的方向中,也就是从更深层次向上返回的过程
假如一个递归函数上
def di(n)
before_logic
di(n-1)
after_logic
而且整个过程一定是:
- 逐步向更深层次调用,并同时处理返回前的代码逻辑,即是
before_logic
- 执行到结束条件,也就是递归出口处,并得到最深层处理的结果
- 逐步向上层返回,并同时处理返回时的代码逻辑,即是
after_logic
1.2.2 有返回值
- 阶乘
简单来说,有返回值和无返回值在过程上没有区别,区别只是在第三步中,有返回值的话会有一个return
,把下一层的结果返回给上一层
也就是说,有返回值的第三步after_logic
是return di(n-1)
,而无返回值的第三步却不是return
- 形式1
def fa(n):
if n == 1:
return 1
return fa(n-1) * n
print (fa(4))
结果是
120
- 形式2
打印每一步结果如下:
def fa(n):
if n == 1:
print (1," : ",1)
return 1
m = fa(n-1) * n
print (n," : ",m)
return m
print (fa(4))
结果是:
1 : 1
2 : 2
3 : 6
4 : 24
5 : 120
120
所以递归中:下面两句等价
return fa(n-1) * n
## --或者--
m = fa(n-1) * n
return m
结合形式2与上图的调用关系可以看出,整个过程是先到达最深的那一层,然后才开始一层一层地向上return
这种情况是把最深一层的值一层一层地向上传递,在传递过程中的每一层,对接收到的值可以进行统一规则的处理(比如上例中是fa(n-1) * n
)
这就相当于第三步中,在返回结果中进行两步逻辑
- 将每一层的处理逻辑结果 * n
return
1.2.3 多重递归
- Fibonacci数列
- 汉诺塔
汉诺塔
def fib(n):
if n == 1 or n ==2:
return 1
return fib(n-1) + fib(n-2)
print (fib(5))
或者
def fib(n):
if n == 1 or n ==2:
return 1
m = fib(n-1) + fib(n-2)
return m
print (fib(5))
或者
def fib(n):
if n == 1 or n ==2:
return 1
s = fib(n - 1)
t = fib(n - 2)
return s + t
print (fib(5))
过程如下:
可以看出,整个流程几乎是按照上图中的箭头方向从上往下走过来的
这和前面的递归形式其实本质上是一样的
def di(n)
di(n1)
di(n2)
这个递归过程其实是分开两步的
第一步
di(n1)
第二步
di(n2)
从整体大步骤上来讲,只有两步,先是di(n1)
,再是di(n2)
也就是di(n1)
全部执行完后,返回到main出发点后,再执行di(n2)
从小步骤上来讲,无论是di(n1)
还是di(n2)
,再向下一层执行的过程是相同的。(也就是图中的意思),都是从最深层回到上一层的出发点后,出现分支。
1.3 递归种类
即1.2中的各种样式
1.3.1 尾递归
- 比如阶乘
递归调用语句只有一个,而且是处在算法的最后
1.3.2 单向递归
- 比如Fibonacci数列
单向递归是指递归算法中虽然有多处递归调用语句,但各递归调用语句的参数之间没有关系,并且这些递归
调用语句都处在递归算法的最后。
2. 迭代
迭代:利用变量的原值推算出变量的一个新值.如果递归是自己调用自己的话,迭代就是A不停的调用B.
递归中一定有迭代,但是迭代中不一定有递归,大部分可以相互转换.能用迭代的不用递归,递归调用函数,浪费空间,并且递归太深容易造成堆栈的溢出.
# 这是递归
def funA(n):
if n < 1:
return 1
return n + funA(n-1)
# 这是迭代
def funB(n):
s = 0
for i in range(1,n):
s = s + i
return s