递归通俗来说就是函数自己调用自己,并且每调用一次,其子问题会相对简单,复杂度会相对降低。以下用经典的汉诺塔问题来解释递归的思路和过程并通过python实现。
1.汉诺塔问题
汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。
这个问题的关键在于两点:
1.一次只能移动一个圆盘;
2.任何时候都只能大圆盘在下,小圆盘在上。
2.汉诺塔递归分析
如果只有1个圆盘,很简单,只要直接把圆盘从a拿到c,操作如下:
a—>c;
如果有2个圆盘,也好说,先把小圆盘放到b,然后把大圆盘当到c,最后把b上面的圆盘放到c,也就是如下操作:
a—>b;
a—>c;
b—>c;
但是问题来了,如果有3个、4个甚至是n个呢?
解决这个问题的关键在于理解递归,2个圆盘的时候能按要求把圆盘从a放到c上,那3个圆盘的时候是不是能先只管前2个,先把前2个按规则放到b,再把最大的圆盘放到c,最后再按规则把b上的2个圆盘放到c,这不就搞定了吗?同样,3个圆盘能搞定,4个圆盘的时候借助3个圆盘的移动方法不也能搞定吗?那n个的时候通过n-1个圆盘过渡也就解决了。
以此类推,当有n个圆盘时,可以先考虑把前n-1个圆盘放到b,再把第n个最大的圆盘放到c,最后把b上的圆盘放到c。借用“码农翻身”公众号图片说明,
3.python实现:
#pyhton3.6
#汉诺塔问题
def whl_hannuo(a,b,c,n):
#一个盘子时,直接从a移到c
move = 0
if n==1:
print(a,'--->',c)
return 1
#2个盘子时,先把小盘子移到b,再把大盘子移到c,最后把b上的小盘子移到c
if n==2:
print(a,'--->',b)
print(a,'--->',c)
print(b,'--->',c)
return 3
#n个盘子时,先借助c将n-1个盘子移到b,再将第n个盘子直接移到c,最后再将b上的n-1个盘子借助a移动到c,搞定
move += whl_hannuo(a,c,b,n-1)
move += whl_hannuo(a,b,c,1) #这里即表示将第n个盘子直接移到c
move += whl_hannuo(b,a,c,n-1)
return move #返回移动次数
#测试一下
a = 'A'
b = 'B'
c = 'C'
n = 3
whl_hannuo(a,b,c,n)
#输出结果为:
A ---> C
A ---> B
C ---> B
A ---> C
B ---> A
B ---> C
A ---> C
7
上面是为了便于理解,其实可以写的更简单:
#pyhton3.6
#汉诺塔问题
def whl_hannuo(a,b,c,n):
#一个盘子时,直接从a移到c
move = 0
if n==1:
print(a,'--->',c)
return 1
#n个盘子时,先借助c将n-1个盘子移到b,再将第n个盘子直接移到c,最后再将b上的n-1个盘子借助a移动到c,搞定
move += whl_hannuo(a,c,b,n-1)
move += whl_hannuo(a,b,c,1) #这里即表示将第n个盘子直接移到c
move += whl_hannuo(b,a,c,n-1)
return move #返回移动次数
#测试一下
a = 'A'
b = 'B'
c = 'C'
n = 3
whl_hannuo(a,b,c,n)
#输出结果为:
A ---> C
A ---> B
C ---> B
A ---> C
B ---> A
B ---> C
A ---> C