递归是一种迭代实现方法 通过一个函数在执行过程中一次或多次调用其本身来解决问题 递归包括递归出口和递归体
一 说明性的例子
1 阶乘函数
对于任何整数n>=0
n!= 1 n=0 递归出口
n*(n-1)(n-2)…32*1 n>=1 //递归体
阶乘函数的递归实现
def factorial(n):
if n==0:
return 1
else:
return n*factorial(n-1)
2 绘制英式标尺
def draw_line(tick_length,tick_label=''):
line='-'*tick_length
if tick_label:
line+=' '+tick_label
print(line)
def draw_interval(center_length):
if center_length>0:
draw_interval(center_length-1)
draw_line(center_length)
draw_interval(center_length-1)
def draw_ruler(num_inches,major_length):
draw_line(major_length,'0')
for j in range(1,num_inches+1):
draw_interval(major_length-1)
draw_line(major_length,str(j))
draw_ruler(2,5)
运行结果
3 二分查找
二分查找用于在一个含有n个元素的有序序列中有效的定位目标值
将一个序列根据中间值mid一分为二,如果目标值x<mid 则在左边的一半中进行查找如果目标值x>mid 则在右边的一半中查找,因为每次查找都可以将一半的数给排除所以也叫二分查找,折半查找
首先low=0,high=n-1
mid=|(low+high)/2|(向下取整)
考虑以下三种情况
1 如果目标值等于[mid]中数据,说明查找成功
2如果目标值<[mid]中数据,对前一半序列重复这一过程,即索引的范围为从low到mid-1
3如果目标值>[mid]中数据,对后一半序列重复这一过程,即索引的范围为从mid+1到high
如果查找范围[low,high]为空,说明查找不成功
时间复杂度为o(log n)
def binary_search(data,target,low,high):
if low>high:
return -1
else:
mid=(low+high)//2
if data[mid]==target:
return mid
elif target>data[mid]:
return binary_search(data,target,mid+1,high)
else:
return binary_search(data, target, low, mid-1)
data=[1,2,3,4,5,6,7,8,9,10]
print(binary_search(data,1,0,9))
print(binary_search(data,11,0,9))
3文件系统
1现代操作系统用递归的方式来定义文件系统目录(有时也称为"文件夹")也就是说一个文件系统包括一个顶级目录,这个目录包括文件和其他目录,其他目录也可以包括文件和其他目录,以此类推。操作系统允许嵌套任意深度的目录
1考虑这样一个算法:计算嵌套在一个特定目录中所有文件和目录的总磁盘使用情况
一个条目的累计磁盘空间可以用简单的递归算法来计算 它等于条目使用的直接磁盘空间加上直接存储在该条目中所有条目使用的累计磁盘空间之和
python的操作系统模块 :该模块提供了强大的与操作系统交互的工具
需要以下四个函数
1os.path.getsize(path):返回由字符串路径(例如:/user/rt/courses)标识的文件或者目录使用的即时磁盘空间大小(单位是字节)
2os.path.isdir(path)如果字符串路径指定的条目是一个目录,则返回True;否则,返回False
3os.listdir(path) 返回一个字符串列表,它是字符串路径指定的目录中所有条目的名称
4 os.path.join(path,filename) 生成路径字符串和文件名字符串,并使用一个适当的操作系统分隔符在两者之间分隔。返回表示文件完整路径的字符串
import os
def disk_usage(path):
total=os.path.getsize(path)
if os.path.isdir(path):
for filename in os.listdir(path):
childpath=os.path.join(path,filename)
total+=disk_usage(childpath)
print('{0:<7}'.format(total),path)
return total;
二 python中的最大递归深度
1在递归的误用中一个危险就是无限递归,无限递归会迅速耗尽计算资源,为了避免无限递归。python限制了可以同时有效激活的函数的总数。这个极限取决于python的分配但典型的默认值是1000.如果达到了这个限制,python解释器就生成了一个RuntimeError消息:超过最大递归深度
python解释器可以动态的重置,以更改默认的递归限制
1用一个名为sys的模块来实现的,该模块支持getrecursionlimit(得到当前递归限制)和setrecursionlimit(重新设置递归限制)函数 .使用示例如下:
import sys
old=sys.getrecursionlimit()
sys.setrecursionlimit(1000000)
三 递归的其他例子
如果一个递归调用最多可以开始一个其他的递归调用,我们称之为线性递归
如果一个递归调用可以开始两个其他递归调用,我们称之为二路递归
如果一个递归调用可以开始三个或者更多其他递归调用,我们称之为多重递归
线性递归
1元素序列的递归求和
观察发现 如果n=0,S中所有n个整数的总和是0(递归出口),否则,序列S的和应为S中前n-1个整数的总和加上S中最后一个元素(递归体)
def linear_sum(data,n):
if n==0:
return 0
else:
return linear_sum(data,n-1)+data[n-1]
data=[1,2,3,4,5,6,7,8,9,10]
print(linear_sum(data,10))
2使用递归逆置序列
逆置让第一个和最后一个交换 ,第二个和倒数第二个交换…使用递归来完成交换
1当startend,这个隐含的范围是空的,当startstop-1时,这个隐含的范围仅含一个元素,这两种情况是不需要执行交换的
1如果n是偶数,最终会到达start==stop这种情况
2如果n是奇数,最终会到达start=stop-1这种情况
def reverse(data,start,end):
if start<end-1:
temp=data[start]
data[start]=data[end-1]
data[end-1]=temp
reverse(data,start+1,end-1)
data=[1,2,3,4,5,6,7,8,9,10]
reverse(data,0,10)
print(data)
num=[1,2,3,4,5]
reverse(num,0,5)
print(num)
3用于计算幂的递归算法
def power(x,n):
if n==0:
return 1
else:
return x*power(x,n-1)
改进版
1采用平方技术计算幂函数
用k=|_n/2 _|表示递归的层数,考虑(x^k) ^2这种表示,当n是偶数时,|_n/2 _|=
n//2,因此(x^k) ^2=(x ^(n//2)) ^2=x ^n 当n是奇数时,|n/2|=n-1//2,且(x^k) ^2=x ^(n-1) 因此x ^n=x*(x ^k) ^2
def power(x,n):
if n==0:
return 1
else:
partial=power(x,n//2)
result=partial*partial
if n%2==1:
result=result*x
return result
二路递归
用二路递归递归地计算一个序列的前一半元素的总和和后一半元素的总和然后把两个和加起来
def binary_sum(data,start,end):
if start>=end:
return 0
elif start == end-1:
return data[start]
else:
mid=(start+end)//2
return binary_sum(data,start,mid)+ binary_sum(data,mid,end)