递归是一种解决问题的方法,他会把一个复杂的问题分解为越来越小的子问题,直到问题变得非常容易解决。
举个栗子:计算列表[1,3,5,7,9]的和
你肯定首先会想到使用一个for循环或者while循环,将列表中的所有元素累加求和,没错,这种方法可以!但是你可以利用递归的思想解决这个问题吗?
回归问题本身,让我们来分析列表求和:sum=1+3+5+7+9,还可以用什么方法表示?加法计算是两个数字相加,同理可得sum=(1+(3+(5+(7+9)))),换个括号方向也可以写成sum=((((1+3)+5)+7)+9),基于上述思想,我们可以看到是不用任何循环的思想就可以计算求和问题,用代码表示:
def sum(num_list):
if len(num_list) == 1:
return num_list[0]
else:
return num_list[0]+sum(num_list[1:])
是不是非常amazing?在第五行函数调用了自身!这就是递归函数,他是一种调用自身的函数。
1.要有基本结束条件;
2.所有得操作必须改变自己的状态并朝基本结束条件演近;
3.必须递归的调用函数自身。
还是以上述求和为例,len(num_list)=1
就是基本结束条件,sum(num_list[1:])
就是朝基本结束条件逼近,num_list[0]+sum(num_list[1:])
就是调用了函数自身。
假设将一个十进制的整数10转换为十进制的字符串“10”或者转为二进制的字符串“1010”,用递归的思想在程序中如何实现?
下面我们讨论将十进制的769转换为任意进制的字符串,我们假设有一个字符串str1=“0123456789”,那么只要是小于10的整数都可以用字符串表示出来,例如9可以表示为str1[9]。我们可以将7,6,9拆成三个单独的数字,其中任一个数字都可以用字符串str1表示。
据上述分析确定进位数后,整个算法包含3部分:
1.将原始整数分解为一连串的单个数字;
2.通过在字符串中检索将单个数字转换为字符串;
3.将这些单个字符串连接起来,形成最终的结果。
对应到实际数学思想中,我们参考整数的除法取余思想,769除以10等于76余9
,76再除以10等于7余6
,7除以10等于0余7
,将所有余数组合起来就是769.用代码将769转换为16进制表示出来,如下:
def to_str(num,base):
str1="0123456789ABCDEF"
if num<base:
return str1[num]
else:
return to_str(num/base,base)+str1[num%base]
整数转换为10进制的递归过程如下图所示:
在上图中看起来生成的结果好像顺序错了,从上到下是967,不是769。兄弟,这样理解是错的,回顾下“栈”的相关知识,我们上述代码的第6行是先递归调用,然后添加字符串,所以生成的字符串还是769!
练习:
写一个函数,接受一个字符串为参数,返回一个反向的新字符串。
def unorder(str1):
if len(str1) == 1:
return str1[0]
else:
return str1[-1]+unorder(str1[:-2])
还是实现将一个整数转换为任意进制的问题:
首先写一个栈
类,并将其实例化(否则不方便使用栈的方法):
class Stack:
def __init__(self):
self.items=[]
def isEmpty(self):
return self.items == 0
def push(self,item):
self.items.append(item)
def pop(self):
return self.items.pop()
def size(self):
return len(sel.items)
Stack=Stack()##实例化栈类
其次通过栈帧实现:
def to_str(n,base):
str1='0123456789ABCDEF'
while n>0:
if n<base:
Stack.push(str1[n])
else:
Stack.push(str1[n%base])
n=n//base#整数除法
res=''
while not Stack.isEmpty():
res = res+str1(Stack.pop())
return res
在python中,当一个函数被调用时,系统回分配一个栈帧去处理函数的局部变量,当执行完函数并得到一个返回值时,这个值会留在栈顶等待被调用的函数来处理。例如将整数10转换为2进制的整数在栈帧中的过程如下图所示:
当调用 toStr(2//2,2) 时,会在栈顶留下一个返回值“1”,这个返回值随后会被用于toStr(2//2,2)+convertString[2%2] 中替代toStr(2//2,2),使语句变为” 1”+convertString[2%2],执行后字符串‘10’就会留在栈顶,以此类推,转换为2进制的结果为‘1010’。