递归
递归是什么
递归:在函数内部,可以调用其他函数。
如果函数在内部调用自身本身,则这个函数就是递归函数;
递归特性:
- 1、必须有明确结束条件
- 2、最大递归999层
- 3、每次进入更深递归时,问题规模应比上次递归少
- 4、递归效率不高,递归层次过多会导致栈溢出
#递归
def calc(n)
print(n)
return calc(n+1)
calc(0)
························
#通过递归,使一个数一直除以2,直到不能除为止
def calc(n)
print(n)
if int(n/2) > 0:
return calc(int(n/2))
print("---->",n)
>> 10
>> 5
>> 2
>> 1
>> ----> 1
递归有什么用
递归可以解决很多算法问题,把复杂问题分成小问题;如阶乘和二分查找;
- 求阶乘
任何大于1的自然数 n 阶乘表示方法 n!=1×2×3×...×n n ! = 1 × 2 × 3 × . . . × n 或 n!=n×(n−1)! n ! = n × ( n − 1 ) !
使用递归代码来实现:
# 4! = 4×3×2×1 = 24
def factorial(n):
if n == 0: #是0的时候,就算完了
return 1
return n*factorial(n-1) #每次递归相乘,n值都较之前小1
d = factorial(4)
print(d)
>> 24
- 二分查找
当猜一个取值范围在 [0,100] 的数,每次猜测都会告诉高了或是低了,用最少的次数猜出该数,则可以每次将取值区间一分为二,直到猜对。
那么,我们假定在一个已排序的数组data中,使用二分法查找 n
数组范围是 [low,… ,high],n 就在该范围内
查找的方法是拿low到high的正中间的值,假设是 mid ,来和n相比
如果mid > n ,则n在数组前半部分
否则在后半部分
然后再次折半查找,重复过程,直到找到n位置
代码实现:
data = list(range(101))
def b_search(n,low,high,d): #要找的值n \取值范围[0-101] \列表data
mid = int((low + high)/2)
if low == high:
print("not found")
if d[mid] > n:
print("go left:",low,high,d[mid])
b_search(n,low,mid,d)
elif d[mid] < n:
print("go right",low ,high,d[mid])
b_search(n,mid+1,high,d)
else:
print("find it",d[mid])
b_search(56,0,len(data),data)
>> go right 0 101 50
go left: 51 101 76
go left: 51 76 63
go left: 51 63 57
go right 51 57 54
find it 56
整个运算过程求了 log2100≈7 l o g 2 100 ≈ 7 次。
尾递归
1、如果一个函数中所有递
归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。
2、当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。
3、尾递归函数的特点是在回归过程中不用做任何操作
例如:
def calc(n):
print(n - 1)
if n > -50:
return calc(n-1)
上面的阶乘不是尾递归,因为递归计算最终的return操作是乘法操作。
每个活跃期的返回值都依赖于用n乘以下一个活跃期的返回值,因此每次调用产生的栈帧将不得不保存在栈上直到下一个子调用的返回值确定。
局部变量与全局变量
注:不要在函数内修改全局变量;
更不要在函数内定义全局变量!!!
当全局变量与局部变量重名时,子程序内局部变量起作用,其他地方全局变量起作用
高阶函数
一个函数可以接受另一个函数作为变量,则该函数称为高阶函数
def add(a,b,f):
return f(a)+f(b)
res = add(3,-6,abs) # abs(-5) = 5
print(res)
>> 9