在学习MOOC上嵩天老师讲解的Python语言程序设计中老师在讲解递归用法的时候提到了汉诺塔问题;
这个问题我迟迟难以明白,困扰很久,在多方面资料的搜寻下,终于理解,问题分析思路如下:
有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个黄金圆盘。
游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。
操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
引用于百度百科
在课程中老师讲到递归的定义时,通过类似的数学归纳法(一种数学证明方法)来理解递归;
初中我们都学过数学归纳法,比如我们证明一个定理成立的时候,一般我们采用数学归纳法可以这样证明:
首先证明当N=0的时候,某一个命题成立
接下来假设当N=K时命题成立
进一步证明当N=K+1时,命题也成立
如果这两个步骤都是对的,那我们就能证明某一个命题成立。
这是数学归纳法对递归的一种使用,也可以理解为是数学归纳法思维在编程中的一种体现。
1,首先需要明确基例和链条,然后采用函数+分支语句的写法来完成代码编写。
2,虽然我们需要移动很多圆盘但是我们可以抽象理解,只将n个圆盘化解为n-1个圆盘的搬运,我们只知道递归过程,只关心递归链条,我们只关心当圆盘数量为n的时候,他怎么拆解为当前n与n-1当前之间的一个关系,至于n-1下面怎么去做,我们不需要关心他。
下面给出代码进行分析(附上汉诺塔小游戏辅助理解)
count = 0 #设置一个计数变量count
def hanoi(n, src, mid, dst):
global count #将变量声明为全局变量
设置一个计数变量count,并利用保留字global让count变量在函数中变成全局变量,防止在每次调用时候初值被清零。
再定义四个参数,分别为圆盘的数量n,源头柱子src,过渡柱子mid,目的柱子dst。这里因为方便对应A,B,C三根柱子所以将老师的参数mid和dst互换位置。
count = 0 #设置一个计数变量count
def hanoi(n, src, mid, dst):
global count #将变量声明为全局变量
if n == 1:
print("{}:{}->{}".format(1, src, dst)) #打印A柱到C柱过程
count += 1
用if分支语句先判断基例n=1时相应的变化过程,此时只需要打印出src(A柱)到dst(C柱)的这一个过程,过程用到format方法,使用模板"{}:{}->{}"格式化,再用复合赋值运算符表示变量count的连加计数方法。
count = 0 #设置一个计数变量count
def hanoi(n, src, mid, dst):
global count #将变量声明为全局变量
if n == 1:
print("{}:{}->{}".format(1, src, dst)) #打印A柱到C柱过程
count += 1
else:
hanoi(n - 1, src, dst, mid) #A柱上n-1到B柱利用C柱过渡的过程
print("{}:{}->{}".format(n, src, dst)) #打印A柱剩余n到C柱的过程
count += 1
hanoi(n - 1, mid, src, dst) #B柱上n-1到C柱利用A柱过渡的过程
接着我们判断链条,其中n和n-1的关系在汉诺塔问题中可以参考图解汉诺塔
这样既然是n个圆盘,从A搬到C,我们可以将n个圆盘中的n-1个圆盘,先从A搬到B,这样的话呢,A柱子中就剩下了最后一个圆盘,我们将最后一个圆盘直接搬到C,然后再将B柱子中的n-1个圆盘挪到C柱子上,这样就实现了A柱子的所有圆盘,向C柱子的一个搬运过程。
count = 0 #设置一个计数变量count
def hanoi(n, src, mid, dst):
global count #将变量声明为全局变量
if n == 1:
print("{}:{}->{}".format(1, src, dst)) #打印A柱到C柱过程
count += 1
else:
hanoi(n - 1, src, dst, mid) #A柱上n-1到B柱利用C柱过渡的过程
print("{}:{}->{}".format(n, src, dst)) #打印A柱剩余n到C柱的过程
count += 1
hanoi(n - 1, mid, src, dst) #B柱上n-1到C柱利用A柱过渡的过程
hanoi(3, 'A', 'B', 'C')
print(count)
接着我们打印出来3个圆盘的过程和次数。
count = 0 # 设置一个计数变量count
def hanoi(n, src, mid, dst):
global count # 将变量声明为全局变量
if n == 1:
print("{}:{}->{}".format(1, src, dst)) # 打印A柱到C柱过程
count += 1
else:
hanoi(n - 1, src, dst, mid) # A柱上n-1到B柱利用C柱过渡的过程
print("{}:{}->{}".format(n, src, dst)) # 打印A柱剩余n到C柱的过程
count += 1
hanoi(n - 1, mid, src, dst) # B柱上n-1到C柱利用A柱过渡的过程
hanoi(3, 'A', 'B', 'C')
print(count)