023,递归2 疯狂的兔子
这节课试图了解一下 斐波那契(Fibonacci)数列(黄金分割数列)的递归实现,作为一个例子。
斐波那契(Fibonacci)数列的脑补链接
斐波那契提出一个著名的兔子繁殖问题:
如果一对兔子每月能生一对小兔(一雄一雌),而每对小兔在它出生后的第三个月里,又能开始生一对小兔,假定在不发生死亡的情况下,由一对出生的小兔开始,50个月后会有多少对兔子?
在第一个月时,只有一对小兔子,过了一个月,那对兔子成熟了,在第三个月时便生下一对小兔子,这时有两对兔子。再过多一个月,成熟的兔子再生一对小兔子,而另一对小兔子长大,有三对小兔子。如此推算下去,我们便发现一个规律(表格省略):
由此可知,从第一个月开始以后每个月的兔子总数是:1,1,2,3,5,8,13,21,34,55,89,144,233...。若把上述数列继续写下去,得到的数列便称为斐波那契数列。数列中每个数便是前两个数之和,而数列的最初两个数都是1。
用文字来说,就是费波那契数列由0和1开始,之后的费波那契系数就由之前的两数相加。首几个费波那契系数是(OEIS A000045):
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,………………
特别指出:0不是第一项,而是第零项。——《维基百科》
斐波那契(Fibonacci)数列的迭代实现:
先用数学函数来定义
f(n) :
当n=1 f(n)=1
当n=2 f(n)=1
当n=3 f(n)=2
当n=4 f(n)=3
…
推理:n>2时数列可表达为: f(n)=f(n-1) + f(n-2)
练习:假设我们需要求出经历了20个月后,总共有多少对小兔崽子
普通迭代写法:(实在不会写!!!不知是数学盲还是脑残。。。。)
#知道逻辑但不会写代码,打击太大了。。 def fab(n): n1 = 1 #第一个月1 n2 = 1 #第二个月1 n3 = 1 #第三个月开始,初始化为1 if n < 1: #判断如果月份小于一那就没意义了。设置返回一个 -1 的错误,供后面调用 print('输入有误') return -1 while (n-2) > 0: n3 = n2 + n1 #从第三个月开始,第三个月等于第二个月和第一个月之和,赋值给n3 n1 = n2 #那么第一个月就等于现在的第二个月,也就是n2的值重新赋值给第一个月 n2 = n3 #同理,第二个月等于现在的第三个月,用n3的值重新赋值给第二个月 n -= 1 # 重新赋值之后,循环次数-1 return n3 #返回结果 result = fab(20) if result != -1: print(‘总共有%d对小兔崽子诞生’ % result)
个人理解:迭代需要一个初始值,那么这里给了第一个月和第二个月的初始值,第三个月是前两个月相加,那么第三个月也有一个初始值,也就是2,当月份变化时,每一个迭代都会重新赋值,也就是说也有三个初始值,一个是当前月的值n3,一个是当前月-1的值即n2,还一个是当前月-2的值,即n1,那么n3就是最后要求的结果。
递归写法:
#Fibonacci数列递归写法: def fab(n): #判断n如果小于1返回错误信息 if n < 1: print('输入有误!') return - 1 # 如果没有下面这条if件句,程序将陷入死循环,为什么?????? if n == 1 or n == 2: return 1 else: return fab(n-1) + fab(n-2) result = fab(20) if result != -1: print('总共有%d对小兔子诞生' % result) #我尝试用 def fab(n): return fab(n-1) + fab(n-2) print(fab(20)) #结果返回一个死循环。 #为什么要加上条件语句?如果单单是判断n<2的话,我赋给函数fab(20),并不小于2,
#脑子实在转不过弯来。求明示!!!!!
递归的中心思想就是 分治思想!一个大问题解决不了,那么可以把大问题分解成若干小问题,把若干小问题解决了,那么大问题也就解决了。
但递归也有其缺陷,比如把上面的20改为35,然后运行它,结果发现,递归算法要等那么一秒钟才算出来,如果用迭代,那么结果就是秒出。所以递归要用在适当的位置适当的时机。