首页 > 编程知识 正文

汉诺塔问题一个典型的什么问题,汉诺塔的解法

时间:2023-05-04 22:59:25 阅读:250257 作者:2892

前言

最近在学Python,遇到了经典的递归问题,汉诺塔。算法原理很简单,代码实现也很简单,可谓大道至简。但是这代码的理解,却稍微让人抓狂,特别是递归调用的参数位置。故本文,重点阐述代码实现,而不注重原理阐述。

汉诺塔算法原理 汉诺塔图示  

1,当 n = 1,A直接移动到C

2,当 n > 1 ,设此时 n=n :

把 A 柱子上面的 (n-1) 个盘子,从 A 移动到 B;

把 A 柱子上面的第 n 个盘子由 A 移动到 C;

把第一步 B 柱子上的 (n-1) 个盘子由 B 移动到 C

PS:

     用句大白话来解释这个算法,就是不管有几个盘子(当然至少得2个,一个就太简单了),就把它看作是2个盘子,第一步,把上面的一个盘子,放到辅助列上去,再把下面的盘子放到目的列,然后再把辅助列的盘子放到目的列。完美,大功告成。以图示的ABC列为例,

汉诺塔图示 Python 代码实现 steps = 0 # 步骤序号def hanoi(afford, mid, accept, n): # afford 最初圆盘所在列,提供圆盘的 || mid 中间辅助列 || accept 接受列,圆盘最终移动的列 || n 最初的圆盘的数量 global steps if n == 1: steps = steps + 1 print("[STEP{:>4}] {}->{}".format(steps, afford, accept)) else: hanoi(afford, accept, mid, n - 1) steps = steps + 1 print("[STEP{:>4}] {}->{}".format(steps, afford, accept)) hanoi(mid, afford, accept, n - 1)hanoi('A', 'B', 'C', 2) 运行结果 [STEP 1] A->B[STEP 2] A->C[STEP 3] B->C[Finished in 0.1s] 代码的前世今生

1,还是以上面的图,ABC列为例。我们的终极目标是把A列上的圆盘,全部转移到C列上去。我们想要这样的一个hanoi 函数,它可以帮我们把 A 列的圆盘放到C列上。那么这个函数需要几个参数呢?看图就知道,我们肯定至少需要3个参数,一个来当A列,一个来当C列,一个来当辅助的B列。那圆盘的个数怎么表示?所以我们再加一个圆盘的个数,这就是第四个参数。嗯,目前能想到的,也就这么多了,那就先试试吧。

2,按照刚刚的想法,我们弄出这样一个hanoi,hanoi(参数1,参数2,参数3,参数4) ,hanoi 从出生时起,就有这样的功能,把第一列的圆盘,放到第三列上面去,这里先把参数一放到A列,把参数三放到C列。参数二,是一个辅助参数,,放到B列。参数四,表示一共有多少个圆盘,这里就不说放到D列了,因为看图就知道,我们只需要3列就行,参数4就相当于一个数量标志,附加在ABC列上的一个数量。

3,为了更直观,我们把参数一二三四,弄个具体的名字。于是,天空一声惊雷,Hanoi闪亮登场 。 hanoi(afford, mid, accept, n) 。把 hanoi 的前3个参数,afford,mid,accept,看成ABC三列。我们知道(因为我们就是按照我们最初的想法设计的hanoi),hanoi 提供这样一个功能,把A列的圆盘,放到C列上去。 这里用的是列,不是参数的名字,因为参数的名字你可以随便取,但是ABC列的位置已经固定了。xfdjd定义出 hanoi 的时候,hanoi 的功能和ABC列的位置就确定下来了,就是把A列的圆盘放到C列上去。(当然你可以定义,A列放到B列,或者B列放到C列)每调用一次hanoi,他就会把A列的圆盘,放到C列上去。这里稍微有点绕,我用故事来说。afford,mid,accept 是三个kadjm,afford 要把自己的情报(圆盘)通过 mid 这个线人,传递给老板 accept,由于敌人内部管理严格,只有通过特定的装置(Hanoi)才能传递信息,这个特定的装置Hanoi,是这样工作的,它有三个座位ABC,每次必须同时坐三个人,坐上后,能把A座位上的人的信息通过B座位上的人,传递给C座位上的人。至于afford,mid,accept 这三个人谁坐A,谁坐B,谁坐C,不一定,看谁想传递信息给谁。反正坐在A座位上的人,会把信息传递给C座位上的人。

4,有了大致的思路,我们就来看看实现。

n =1,即 afford 上面只有一个圆盘 一层汉诺塔

目标:

      此时afford在A列,accept在C列,直接把afford上的一个圆盘,放到第三列的accept,不需要通过B来辅助。

实现:

def hanoi(afford, mid, accept, n): # afford 最初圆盘所在列,提供圆盘的 mid 中间辅助列 accept 接受列,圆盘最终移动的列 n 最初的圆盘的数量 global steps if n == 1: steps = steps + 1 print("[STEP{:>4}] {}->{}".format(steps, afford, accept))

 

n = n,即afford上面有 n 个圆盘 n层汉诺塔(把上面的一个看作n-1个)

 目标:

         afford 有n个圆盘,要把上面n-1个圆盘,先放到辅助列mid上去

实现:

       我们知道调用hanoi,就会把第一列的圆盘,放到第三列,那么我们现在在调用hanoi的时候,afford需要坐在A列,mid坐到C列,hanoi就可以把afford上面n-1个圆盘转移到mid,此时注意,我们只转移了n-1个,所以hanoi你们的n这个参数,是n-1

else: hanoi(afford, accept, mid, n - 1)

调用完成后,此时就是这样的,

n-1个圆盘被移到了mid列上

接下来,我们要将afford上的这一个最大的圆盘,交换到accept上,执行 print 即可。(因为我们的print 永远就是将afford上的圆盘,放到accept上)

print("[STEP{:>4}] {}->{}".format(steps, afford, accept))

执行完成后,是这样的

afford 上的一个圆盘,放到了C上

 

最后,我们只需要将辅助列 mid 上的 n-1 个圆盘放到 accept 。当然调用我们的hanoi 。hanoi 的功能是将第一列上的圆盘放到第三列,所以,我们要将mid放到第一列,accept 放到第三列。代码如下

hanoi(mid, afford, accept, n - 1)

执行完成后,是这样的,结束。

最后放一个不一样的参数位置,以及代码实现 steps = 0def hanoi(des, src, mid, n): # des 目的列 src 最初的圆盘列 mid 辅助列 global steps if n == 1: steps = steps + 1 print("[STEP{:>4}] {}->{}".format(steps, src, des)) else: hanoi(mid, src, des, n - 1) steps = steps + 1 print("[STEP{:>4}] {}->{}".format(steps, src, des)) hanoi(des, mid, src, n - 1)hanoi('C', 'A', 'B', 3) # 以3阶汉诺塔为例,C:目的列,A:最初圆盘列,B:辅助列

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。