递归的定义
函数定义中调用函数自身的方式
两个特性:
- 链条:计算过程存在递归链条
例如,n!=n*(n-1)!,n!与(n-1)!就构成了递归链条 - 基例:基础的实例,存在一个或多个不需要再次递归的基例
例如,当n=0时,我们定义它的值为1这就是一种基例,它与其他的值之间不存在递归关系
递归的实现
函数+分支语句
递归本身是一个函数,需要函数定义方式描述,用函数定义名字,在函数中调用本身。在函数内部,我们要区分哪些是基例,哪些是链条,所以我们要使用一个分支语句对输入参数进行判断,基例和链条,分别编写对应代码
def fact(n):
if n == 0:
return 1
else:
return n*fact(n-1)
我们假设参数的初始值为5,当n等于5,它会返回n*fact(n-1)
也就是执行5×fact(4),但是当前程序并没有运算fact(4),不知道fact(4)的值,而fact(4)又调用了一个它自身函数,就需要对当前n等于4的时候的值做运算,计算机会开辟一段新的内存,将计算n等于4的函数的运算值
以此类推,当我们最后在计算机中开辟了一个新的内存,计算fact(0)时,它会返回1,得到1 之后就会返回给fact(1)这段函数,fact(1)执行后它的结果会返回给fact(2),最后返回给fact(5)也就实现了递归。
字符串反转
将字符串s反转后输出
s[::-1]
这是列表切片中达到字符串反转的
递归方式:
def rvs(s):
if s == "":
return s
else:
return rvs(s[1:]+s[0])
字符串的基例就是字符串的最小形式,那就是空字符串,反转,就是它自己,如果字符串等于" "
我们就返回它自身,如果字符串s不是空,它的反转是什么呢,如果要实现递归过程,那就需要递归链条,递归链条很重要的就是,当前操作和之前的一步之间的关系,为了将字符串s进行反转,我们可以将一个字符串的首字符放在其余字符的后面,构成反转,将其余字符看成是反转后的字符,这样我们就完成一次字符串的反转
斐波那契数列
df f(n):
if n == 1 or n == 2 :
return 1
else :
return f(n-1)+f(n-2)
汉诺塔问题
count = 0
def hanoi(n,src,dst,mid): #n圆盘数量,src源柱子,dst目的柱子,mid过渡柱子
global count
if n == 1 :
print("{}:{}->{}".format(n,src,dst))
count += 1
else :
hanoi(n-1,src,mid,dst)
print("{}:{}->{}".format(n,src,dst))
count += 1
hanoi(n-1,mid,dst,src)
n = eval(input())
hanoi(n,"A","B","C")
递归语句中主要在于寻找基例和链条,链条主要是当前操作与前一步操作的关系,在汉诺塔问题中,当前操作是借助过度柱子将盘子从源柱子挪到目的柱子,而前一步操作,源柱子变成了过渡柱子,即借助源柱子,将剩余盘子从过渡柱子挪至目的柱子,仔细分析有两个盘子的时候,挪动最下面的盘子的过程就是当前操,挪动最上面盘子的过程就是前一步操作。