一、基础复习
- 函数的基本用法 创建和调用函数 函数的形参与实参等等
- 函数的几种参数 位置参数、关键字参数、默认参数等
- 函数的收集参数*args **args 解包参数详解
- 函数中参数的作用域 局部作用域 全局作用域 global语句 嵌套函数 nonlocal语句等详解
- 函数的闭包(工厂函数)
- lambda()函数表达式、map()、filter()函数详解
- 生成器的定义、使用和产生生成器的两种方法详解
二、递归
1.函数的递归
递归就是函数调用自身的过程。
例1.1:在funB()里面调用funA()。
>>> def funA():
print("qsjoasj")
>>> def funB():
funA()
>>> funB()
qsjoasj
例1.2:函数自身的调用,没有结束条件会一直循环下去。
>>> def funC():
print("123asas")
funC()
>>> funC() # ctrl+c退出循环
123asas
123asas
123asas
123asas
123asas
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
funC()
File "<pyshell#17>", line 3, in funC
funC()
File "<pyshell#17>", line 3, in funC
funC()
File "<pyshell#17>", line 3, in funC
funC()
[Previous line repeated 309 more times]
File "<pyshell#17>", line 2, in funC
print("123asas")
KeyboardInterrupt
>>>
例1.3:加上一个条件递归语句,让递归在恰当的时候进行回归。
要让递归正常工作,必须要有一个结束条件,并且每次调用都会向着这个结束条件去推进。
>>> def funC(i):
if i >0:
print("AASDDWDA")
i-=1
funC(i)
>>> funC(10) # 执行10次结束递归
AASDDWDA
AASDDWDA
AASDDWDA
AASDDWDA
AASDDWDA
AASDDWDA
AASDDWDA
AASDDWDA
AASDDWDA
AASDDWDA
>>>
2.递归和迭代的对比
例2.1 求一个数的阶乘
方法一:迭代
>>> def factIter(n):
result=n
for i in range(1,n):
result *= i
return result
>>> factIter(5)
120
>>> factIter(10)
3628800
>>>
方法二:递归
思路:定义一个递归函数,它的参数就是每次要运算的这个数值,然后接着让参数在每次调用的时候都递减一下,当检测到参数的值为1的时候就停止递归。
>>> def factRecur(n):
if n==1:
return 1
else:
return n * factRecur(n-1)
>>> factRecur(5)
120
>>> factRecur(10)
3628800
>>>
例2.2 斐波那契数列
方法一:迭代
>>> def fibIter(n):
a=1
b=1
c=1
while n>2:
c=a+b
a=b
b=c
n-=1
return c
>>> fibIter(12)
144
>>> fibIter(120)
5358359254990966640871840
>>>
方法二:递归
递归会导致效率问题,每一次调用递归函数,它并不会立即返回,而是要等到最底层的那个函数返回,然后再一层一层往上走,这个过程及其耗费资源,比如代码中n=120的时候,代码会一直默认执行,此时只有ctrl+c结束任务。
>>> def fibRecur(n):
if n==1 or n==2:
return 1
else:
return fibRecur(n-1) + fibRecur(n-2)
>>> fibRecur(12)
144
>>> fibIter(120) # 迭代次数n为120时,立即出结果。
5358359254990966640871840
>>> fibRecur(120) # 递归120次,代码会一直默认执行,此时只有ctrl+c结束任务。
Traceback (most recent call last):
File "<pyshell#76>", line 1, in <module>
fibRecur(120)
File "<pyshell#73>", line 5, in fibRecur
return fibRecur(n-1) + fibRecur(n-2)
File "<pyshell#73>", line 5, in fibRecur
return fibRecur(n-1) + fibRecur(n-2)
File "<pyshell#73>", line 5, in fibRecur
return fibRecur(n-1) + fibRecur(n-2)
[Previous line repeated 108 more times]
KeyboardInterrupt
3.总结
执行同一个算法时,数字n较小时,迭代和递归效率相同,当数字n较大时,如例2.2迭代进行计算会更加方便。
课后题:
1.递归算法的实现原理什么?
答:函数调用自身。
解析:没错,就是这么简单,但一定要记得设定退出递归的条件,否则就会是有去无回。
2.实现同样的任务,说使用递归的执行效率通常要比迭代低,请问依据是什么?
答:函数重复调用导致的额外开销。
解析:递归效率低是由于函数的重复调用导致的额外开销。
3.请问下面代码中,recsum() 函数被调用了多少次?
>>> def recsum(x):
... if x < 0:
... return x
... else:
... return recsum(x-1) + recsum(x-2)
...
>>> recsum(3)
-11
答:15 次。
解析:
recsum(3)
recsum(2) + recsum(1)
(recsum(1) + recsum(0)) + (recsum(0) + recsum(-1))
(recsum(0) + recsum(-1)) + (recsum(-1) + recsum(-2)) + (recsum(-1) + recsum(-2)) + (-1)
(recsum(-1) + recsum(-2)) + (-1) + (-1) + (-2) + (-1) + (-2) + (-1)
-1 - 2 - 1 - 1 - 2 - 1 - 2 - 1 = -11
4.下面代码利用递归实现将列表的各个元素进行相加,请补全红色方框中的代码,使其能够成功执行并获取结果。
答:
>>> def recsum(x):
... if not x:
... return 0
... else:
... return x[0] + recsum(x[1:])
5.下面代码利用递归实现将嵌套列表的各个元素进行相加,请补全红色方框中的代码,使其能够成功执行并获取结果。
答:
>>> def sumtree(x):
... total = 0
... for i in x:
... if type(i) is not list:
... total += i
... else:
... total += sumtree(i)
... return total
...
>>> sumtree([1, 2, 3, [4, 5, [6, 7, 8, [9, 10]]]])
55
题目来自链接: 小甲鱼函数(VIII)