递归是指一个函数在其内部调用自身的方法,这个过程可以反复嵌套多层,
1.官方说法是1000层,实测第997层之后就不再调用了,这个层数是可以修改的,但一般不会这么做.
2.递归的出口和结束不一定是return,以遍历文件夹下的各个文件名为例,print所有文件名即可结束递归
3.但是如果需要最后一次递归的返回值(比如下面提到的第三种二分法),则需要在每次调用的时候都返回该函数
此时return收到的是上一次函数的返回值,层层追回到最后一层得到整个递归的最终返回结果,并以这种形式输出这个值
函数的return语句只能在调用的这一层起作用,不加处理的话,是不会出现在调用这个函数所在语句的嵌套层之外的,会使递归的打印结果变成None
二分法的机制避免了依次遍历每一个元素的低效率操作;而是把每次比较元素的内容都限制在上一次比较涉及范围的二分之一里.
显然,二分法的优点是能够大大提高寻找的效率、节约空间。
但是,二分法的缺点也是显而易见的,为了让算法内部每一次的分半是有意义的,必须要求在一个有序的对象中寻找目标元素.
下面从三个不同的思路写一下二分法的程序
方法一:不使用递归
二分法的寻找次数是不能确定的,
这就意味着可以通过设置有条件的while循环来满足持续的寻找需求,for循环不行
l = [2, 3,88,100]
def func(lst,n):
left = 0
right = len(lst)-1
while left <= right: #如果一直无法找到,不满足while条件,即left>right
mid = (left + right)//2 #地板除取整数部分
if n == lst[mid]:
print('在列表内')
print('是列表里的第%d个数' %(mid+1))
break #找到之后及时退出循环
elif n < lst[mid]:
right = mid - 1
else:
left = mid + 1
else:
print('没找到')
func(l,3)
方法二:使用递归,改变left和right的值
l = [2,3,88,100]
def func(left,right,lst,n):
mid = (left + right)//2 #使用递归的话,在本算法中需要在最开始手动输入左右两端的数值,作为函数的参数之一,
#如果在函数内部将其分别设定为0和len(l)则无法有效在下一次调用时改变left和right的值
#注意,此处没有将下一层函数的值返回到这一层,因为最终递归的出口是一句print()语句,无需返回
#同理,此处也无需返回
if left <= right:
if n == lst[mid]:
print ('在列表内')
return '是列表里的第%d个数' %(mid+1)
elif n < lst[mid]:
right = mid - 1
return func(left,right,lst,n)
else:
left = mid + 1
return func(left,right,lst,n)
else:
print('没找到')
return -1
print(func(0 , len(l)-1 , l , 88))
方法三:使用递归,改变被查的列表
l = [2,3,88,100]
def func(lst,n):
left = 0
right = len(lst) #此处不能写为len(lst)-1,会使最左边的2找不到,应该的[2]就变成了[]
#在这个算法中,取列表的右侧是不受影响的,因为此时最右端是自动到全部的最后
#如果想加上'-1',那么在下面的[:mid-1]去掉'-1'
mid = (left + right)//2 if right<0: return ('没找到') #此处return修改之后效果同下 else: if n > lst[mid]: lst = lst[mid+1:] print(lst) elif n < lst[mid]: lst=lst[:mid-1] print(lst) else: return ('找到了') #此处若把return改为print,此处将不会把下一层函数的值返回到这一层,因为最终递归的出口是一句print()语句,无需返回,下面的一句也不需要加return
return func(lst, n)
print(func( l ,100))