递归
有人说,天才使用递归,因为递归大大的减少了程序员的代码量,而且能方便程序员实现许多的功能,但从内存等角度上,比如数据结构里提到的空间复杂度和时间复杂度来说,递归算法很多情况下的时间复杂度往往是很大的,并称不上一个好的算法,但是递归在某些方面,却又有别的方式无法媲美的优点,今天举三个例子,来温习前几天学习的递归。
1. 阶乘的两种实现:
#非递归:
def jiecheng(n):
y=1
for i in range(1,n+1): #range值取不到stop值本身,故加一
y*=i
return y
#递归实现:
#提前在程序开头import sys
sys.setrecursionlimit(100) #设置最大递归层数为100 是一个python的保护措施
def jiecheng2(x):
if x==0: #0的阶乘为1
y=1
else:
y=x*jiecheng2(x-1)
return y
下面用求6000的阶乘对比一下两种算法的优劣:
非递归:
图片仅为结果的一小部分,但是结果仅在一眨眼的情况下就运行出来了
递归:
可以看到,这里递归6000层,超过了我开头设置的100层,所以我们把递归允许层数设置大一点,再来尝试一下:
import sys
sys.setrecursionlimit(10000) #设置最大递归层数为10000
Process finished with exit code -1073741571 (0xC00000FD)
查看问题的根源在于递归导致的栈溢出
解决办法可参考:谁说Python不能尾递归优化
2. 斐波那契数列的两种实现:
#斐波那契数列 F(n) = 1(n=1,2) ; F(n-1)+F(n-2)
# 递归实现
def fibonacci(n):
if(n<1):
print('请重新输入!不可小于1!')
y=-1
elif(n==1):
y=1
elif n==2:
y=1
else:
y=fibbonacci(n-1)+fibbonacci(n-2)
return y
n=int(input('请输入几个月:\n'))
print('递归', n, ' 个月后共有:', fibonacci(n), ' 对兔子')
# 非递归实现
def fab(n):
if(n<1):
print('请重新输入!不可小于1!')
y=-1
elif(n==1):
y=1
elif n==2:
y=1
else:
n1=1
n2=1
n3=1
while(n-2>0):
n3=n2+n1
n1=n2
n2=n3
n-=1
y=n3
return y
print('非递归:20个月后共有:', fab(20), ' 对兔子')
对于斐波那契数列的递归和非递归算法进行测试,仍然是非递归比较优越。
但是这么说我们的递归方法,除了减少程序的代码量,就真的别无用处了吗?当然不是!
请看我们的著名的汉诺塔算法:
3. 汉诺塔的递归实现:
递归的正确使用 – 汉诺塔
第一个参数是起始柱,第二个参数是过渡柱,第三个参数是终点柱
def hanoi(n,x,y,z):
if n==1:
print(x, '-->', z)
else:
hanoi(n - 1, x, z, y) #将前n-1从x移动到y上
print(x,'-->',z) #将最一个盘子从x移动到z上
hanoi(n - 1, y, x, z) #将前n-1从y移动到z上
# 注意以上两次递归调用汉诺塔算法,起始柱,过渡柱,目标柱的变化!
n=int(input('请输入汉诺塔的层数:\n'))
hanoi(n,'x','y','z')
递归大大的减少了程序员的代码量,而且能方便程序员实现许多的功能,但是也比较吃内存吃时间,要在内存,时间和算法之间寻求一个平衡点,递归的用法还需斟酌再三,但我认为不一定是天才才可用递归,相信我们多学多练,也能找到那个平衡点的!