函数(七)——递归函数与二分法
一、递归函数
1.递归调用的定义
递归调用是函数嵌套调用的一种特殊形式,函数在调用时,直接或间接调用了自身,就是递归调用
2.递归分为两个阶段:递推,回溯
#图解。。。
# salary(5)=salary(4)+300
# salary(4)=salary(3)+300
# salary(3)=salary(2)+300
# salary(2)=salary(1)+300
# salary(1)=100
#
# salary(n)=salary(n-1)+300 n>1
# salary(1) =100 n=1
def salary(n):
if n == 1:
return 100
return salary(n-1)+300
print(salary(5))
3.python中的递归效率低且没有尾递归优化
#python中的递归
python中的递归效率低,需要在进入下一次递归时保留当前的状态,在其他语言中可以有解决方法:尾递归优化,即在函数的最后一步(而非最后一行)调用自己,尾递归优化:http://egon09.blog.51cto.com/9161406/1842475
但是python又没有尾递归,且对递归层级做了限制
#总结递归的使用:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
4.可以修改递归最大深度:import sys
import sys
sys.getrecursionlimit()
sys.setrecursionlimit(2000)
n=1
def test():
global n
print(n)
n+=1
test()
test()
虽然可以设置,但是因为不是尾递归,仍然要保存栈,内存大小一定,不可能无限递归
二、二分法
想从一个按照从小到大排列的数字列表中找到指定的数字,遍历的效率太低,用二分法(算法的一种,算法是解决问题的方法)可以极大低缩小问题规模
l=[1,2,10,30,33,99,101,200,301,402] #从小到大排列的数字列表
def search(num,l):
print(l)
if len(l) > 0:
mid=len(l)//2
if num > l[mid]:
#in the right
l=l[mid+1:]
elif num < l[mid]:
#in the left
l=l[:mid]
else:
print('find it')
return
search(num,l)
else:
#如果值不存在,则列表切为空
print('not exists')
return
search(100,l)
实现类似于in的效果
l=[1,2,10,30,33,99,101,200,301,402]
def search(num,l,start=0,stop=len(l)-1):
if start <= stop:
mid=start+(stop-start)//2
print('start:[%s] stop:[%s] mid:[%s] mid_val:[%s]' %(start,stop,mid,l[mid]))
if num > l[mid]:
start=mid+1
elif num < l[mid]:
stop=mid-1
else:
print('find it',mid)
return
search(num,l,start,stop)
else: #如果stop > start则意味着列表实际上已经全部切完,即切为空
print('not exists')
return
search(301,l)
实现类似于l.index(30)的效果