what's the python之递归函数、二分算法与汉诺塔游戏

what's the 递归?

  递归函数的定义:在函数里可以再调用函数,如果这个调用的函数是函数本身,那么就形成了一个递归函数。

  递归的最大深度为997,这个是程序强制定义的,997完全可以满足一般情况下用到递归的情形。

#最大997层
def foo(n):
    print(n)
    n += 1
    foo(n)
foo(1)

 

举个栗子:

  假设你想知道A的年龄,但你只知道A比B大2岁,B又比C大两岁,C又比D大两岁,D比E大两岁,恰好你知道E的岁数,那是不是就能知道A的岁数了呢,这就可以组成一个递归。那我们假设E的岁数是20

def age(n):
    if n == 1:
        return 20
    else:
        return age(n-1)+2

print(age(5))

 

递归小练习

def func1(x):
    print(x)
    func1(x-1)

def func2(x):
    if x>0:
        print(x)
        func2(x-1)

def func3(x):
    if x>0:
        func3(x-1)
        print(x)
        
func1(5)    #死循环
func2(5)    #5 4 3 2 1
func3(5)    #1 2 3 4 5
练习1
def test(n):
    if n == 0:
        print("我的小鲤鱼", end='')
    else:
        print("抱着", end='')
        test(n-1)
        print("的我", end='')
def func(n):
    print('吓得我抱起了', end='')
    test(n)

func(3)#吓得我抱起了抱着抱着抱着我的小鲤鱼的我的我的我
练习2(吓得我抱起了抱着抱着抱着我的小鲤鱼的我的我的我)

 

二分算法

  递归函数的一个经典用法就是二分算法,二分算法的意思是用对半切查找的方式从由一群由小到大的数组成的列表中找到要找的数字的方法

举个栗子:

l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]
                                       #优化后的代码
def func(l,aim):                          def func(l, aim,start = 0,end = len(l)-1 ):                                 
    mid = (len(l)-1)//2                     mid = (start+end)//2
    if l:                                     if not l[start:end+1]:
        if aim > l[mid]:                       return
            func(l[mid+1:],aim)             elif aim > l[mid]:
        elif aim < l[mid]:                     return func(l,aim,mid+1,end)
            func(l[:mid],aim)               elif aim < l[mid]:
        elif aim == l[mid]:                   return func(l,aim,start,mid-1)
            print("bingo",mid)              elif aim == l[mid]:
    else:                                         print("bingo")
        print('找不到')                            return mid
func(l,66)                                index = func(l,68)
func(l,6)                                 print(index)

 

以上就是简单的二分算法,当然因为切片会造成内存的损耗,所以我们还可以将以上代码进行改进

def bin_search_rec(data_set,value,low,high):
    if low <= high:
        mid=(low+high) // 2
        if data_set[mid] == value:
            return mid
        elif data_set[mid] > value:
            return bin_search_rec(data_set,value,low,mid-1)
        else:
            return bin_search_rec(data_set,value,mid+1,high)
    else:return None

l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]
a=bin_search_rec(l,66,2,88) 
print(a)#2

 

汉诺塔游戏

  汉诺塔游戏是法国数学家爱德华·卢卡斯编写的一个印度的古老传说:大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。 大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。 在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。 64根柱子移动完毕之日,就是世界毁灭之时。

 

   这个游戏可以用递归的思想解决,首先我们来捋一捋思路:

      两个盘子时:

      1. 把小圆盘从A移动到B
      2. 把大圆盘从A移动到C
      3. 把小圆盘从B移动到C

      n个盘子时:

      1. 把n-1个圆盘(除去最后一个以外的所有)从A经过C移动到B
      2. 把第n个圆盘(最后一个)从A移动到C
      3. 把n-1个小圆盘从B经过A移动到C

 接下来我们来写代码

a=0
def hanoi(n,x,y,z):
    global a
    if n==1:
        a+=1
        print(x,'-->',z)
    else:
        hanoi(n-1,x,z,y)#将前n-1个盘子从x移动到y上
        hanoi(1,x,y,z)#将最底下的最后一个盘子从x移动到z上
        hanoi(n-1,y,x,z)#将y上的n-1个盘子移动到z上

n=int(input('请输入汉诺塔的层数:'))

hanoi(n,'柱子A','柱子B','柱子C')
print('一共用了%s次'%a)
"""
假设我们的汉诺塔层数为3
请输入汉诺塔的层数:3
柱子A --> 柱子C
柱子A --> 柱子B
柱子C --> 柱子B
柱子A --> 柱子C
柱子B --> 柱子A
柱子B --> 柱子C
柱子A --> 柱子C
一共用了7次
"""

 

  汉诺塔移动次数的递推式:h(x)=2h(x-1)+1。h(64)=18446744073709551615 假设婆罗门每秒钟搬一个盘子,则总共需要5800亿年!所以世界是不会毁灭的哇咔咔~

 

posted @ 2017-08-05 18:57  ''竹先森゜  阅读(2290)  评论(0编辑  收藏  举报