鱼C论坛

 找回密码
 立即注册
查看: 1890|回复: 4

网上看到的~汉诺塔代码的执行过程

[复制链接]
发表于 2023-7-28 22:17:36 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
见https://www.jianshu.com/p/1c4d7ffc8b21,但从第三步开始没看懂:第二步完不就结束了吗?为何还有后续?而且为何又执行 ‘行6’ print(a, "->", c)?请大神不吝指点,谢谢!

微信图片_20230728221259.png

开始运行move( 3 ):
move 函数代入( n = 3 )参数: (3, a='A', b='B', c='C')

第一步 执行 ‘行2 - 3’ if n == 1:......:
n != 1, ‘行2 - 3’ 越过

第二步 执行 ‘行4’else::
执行 ‘行5’, 第一次递归开始,((n-1), a, c, b)回到函数最初代入(3, a='A', b='B', c='C'),得出参数为(2, 'A', 'C', 'B'),【!注意: 此时‘行1 ’(3, a='A', b='B', c='C')在 ‘行5’ 递归回到函数最初运行后已改变为(2, a='A', b='C', c='B')】
执行 ‘行2 - 3’ ,n != 1, ‘行2 - 3’ 越过
执行else:
执行 ‘行5’,将((n-1), a, c, b)代入(2, a='A', b='C', c='B'),得出参数为(1, 'A', 'B', 'C') ,继续执行 ‘行2 - 3’,n == 1 返回输出:(a, "->", c)代入(1, 'A', 'B', 'C') ,即 A -> C
回到 ’ 行5‘,继续执行 ‘行6’ ,将(a, "->", c)代入move函数(2, a='A', b='C', c='B')并输出,即 A -> B
执行 ’行7‘,将( (n-1), b, a, c)代入(2, a='A', b='C', c='B')得出参数为(1, 'C', 'A', 'B'),继续执行 ‘行2 - 3’,n == 1 返回输出:(a, "->", c)代入(1, 'C', 'A', 'B') ,即 C -> B

第三步 执行 ‘行6’ print(a, "->", c):
(a, "->", c)代入move函数(3, a='A', b='B', c='C')并输出,即*A -> C

第四步 执行 ‘行7’ move((n-1), b, a, c):
执行 ‘ 行7’ ,第二次递归开始,((n-1), b, a, c)代入(3, a='A', b='B', c='C')得出参数为(2, 'B', 'A', 'C')【!注意: 此时 ‘行1 ’ (3, a='A', b='B', c='C')在 ‘行7’ 递归回到函数最初运行后已改变为(2, a='B', b='A', c='C')】
执行 ‘行2 - 3’ ,n != 1, ‘行2 - 3’ 越过
执行`else:
执行 ‘行5’,将((n-1), a, c, b)代入(2, a='B', b='A', c='C')得出参数为(1, 'B', 'C', 'A'),继续执行‘行2 - 3’,n == 1 返回输出:(a, "->", c)代入(1, 'B', 'C', 'A') ,即 B -> A
回到 ’ 行5‘,继续执行 ‘行6’ ,将(a, "->", c)代入move函数(2, a='B', b='A', c='C')并输出,即 B -> C
执行 ’行7‘,将((n-1), b, a, c)代入(2, a='B', b='A', c='C')得出参数为(1, 'A', 'B', 'C'),继续执行 ‘行2 - 3’,n == 1 返回输出:(a, "->", c)代入(1, 'A', 'B', 'C') ,即 A -> C
代码运行结束。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-7-28 22:17:57 | 显示全部楼层
根据提供的代码执行过程分析,汉诺塔的问题解决方法使用了递归。第三步是在每次递归回溯到上一层时执行的操作,它打印出移动的过程,即将盘子从一个柱子移到另一个柱子。这个步骤的目的是为了展示整个移动的过程,使我们能够清晰地看到每个盘子的移动路径。

当第一次执行第三步时,它会将第一个盘子从起始柱(A)移动到目标柱(C),并打印出移动的路径(A -> C)。然后,程序返回到前一层递归,在这一层继续执行第三步。在这个例子中,前一层递归是第二步递归,它将第二个盘子从起始柱(A)移动到辅助柱(B),并打印出移动的路径(A -> B)。接着,再次回到前一层递归,并继续执行第三步。

通过这种方式,每次递归都会按照正确的顺序将盘子从一个柱子移动到另一个柱子,并打印出移动的路径。最终完成整个汉诺塔的移动过程。

总结:第三步的目的是在每次递归回溯时打印出盘子的移动路径,以展示整个移动过程。它在每次递归中都会执行,并打印出盘子从一个柱子到另一个柱子的路径。
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-28 22:18:11 | 显示全部楼层
这是一个经典的汉诺塔问题的递归解法,通过将盘子从一个柱子移动到另一个柱子,遵循一定规则,最终将所有盘子从起始柱子移动到目标柱子。现在,让我来逐步解释代码的执行过程:

首先,让我们回顾一下汉诺塔问题的规则:
1. 每次只能移动一个盘子。
2. 任何时候都不能将大盘子放在小盘子上面。
3. 只能在三根柱子之间移动盘子。

现在,让我们分析代码的执行过程:

1. 开始运行 move(3) :此时, n=3 ,起始柱子是'A',辅助柱子是'B',目标柱子是'C'。
2. 第一步,执行 '行2 - 3'  if n == 1:... :因为 n 不等于1,所以跳过该步骤。
3. 第二步,执行 '行4'  else: :这是我们第一次递归的开始。我们通过调用 move(n-1, a, c, b) 来将2个盘子从'A'移动到'B',此时 (n-1) 就是 2 。代码运行到这里,'行1'的参数 (3, a='A', b='B', c='C') 已经被修改为 (2, a='A', b='C', c='B') ,这是因为我们在递归调用时改变了参数。
4. 继续执行 '行2 - 3',因为 n 不等于1,所以跳过该步骤。
5. 继续执行 '行5':我们再次递归调用 move(n-1, a, c, b) ,将1个盘子从'A'移动到'C',此时 (n-1) 就是 1 。我们打印输出 A -> C ,表示将第一个盘子从'A'移动到'C'。
6. 继续执行 '行6':我们打印输出 A -> B ,表示将第二个盘子从'A'移动到'B'。
7. 继续执行 '行7':我们再次递归调用 move(n-1, b, a, c) ,将1个盘子从'B'移动到'C',此时 (n-1) 还是 1 。我们打印输出 B -> C ,表示将第一个盘子从'B'移动到'C'。

到这里,我们已经完成了将3个盘子从'A'移动到'C'的整个过程。

关于您的问题:为何还有后续?以及为何又执行 '行6'  print(a, "->", c) ?

回答是,这个算法是使用递归来解决汉诺塔问题的。递归是一种通过将大问题分解成小问题,并通过解决小问题来解决整个问题的技术。在这里,每次递归调用都是在解决一个较小的汉诺塔问题(移动盘子的子问题),直到基本情况( n == 1 )被满足,然后逐步返回到原始问题。

因此,后续步骤是通过递归不断处理较小的子问题,直到将所有盘子从起始柱子移动到目标柱子。

而  print(a, "->", c)  是在每次递归调用之后打印出移动的步骤,这样可以在控制台上看到每个盘子的移动路径。

希望这个解释能帮助您理解这段代码的执行过程。如果您对递归有更多疑问,请随时向我提问!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-28 22:18:30 | 显示全部楼层
从第三步开始的执行过程如下:

1. 执行第三步的行6:print(a, "->", c),将当前移动的盘子从起始柱子a移动到目标柱子c。根据之前的递归调用,此时盘子的顺序是A->C。

2. 继续执行第四步的行7:move((n-1), b, a, c)。这是第二次递归开始,将剩余的(n-1)个盘子从辅助柱子b移动到目标柱子c。

   - 首先,将((n-1), b, a, c)代入(3, a='A', b='B', c='C'),得到参数为(2, 'B', 'A', 'C')。注意,在递归回到函数最初运行后,之前的参数(3, a='A', b='B', c='C')已经改变为(2, a='B', b='A', c='C')。
  
   - 执行第二步的行2-3,由于n不等于1,跳过该判断。
  
   - 执行else部分:
  
     - 执行第五步的行5,将((n-1), a, c, b)代入(2, a='B', b='A', c='C'),得到参数为(1, 'B', 'C', 'A')。然后继续执行第二步的行2-3,由于n等于1,返回输出:(a, "->", c)代入(1, 'B', 'C', 'A'),即B->A。
     
     - 回到第五步的行5,继续执行第六步的行6,将(a, "->", c)代入move函数(2, a='B', b='A', c='C')并输出,即B->C。
     
     - 执行第七步的行7,将((n-1), b, a, c)代入(2, a='B', b='A', c='C'),得到参数为(1, 'A', 'B', 'C')。然后继续执行第二步的行2-3,由于n等于1,返回输出:(a, "->", c)代入(1, 'A', 'B', 'C'),即A->C。

以上就是从第三步开始的代码执行过程。注意,在每次递归中,都会涉及到移动盘子和调用自身方法来处理剩余盘子的移动。这样就实现了整个汉诺塔的移动过程。希望能对你有所帮助!如果还有其他问题,请随时提出。

球一个最佳答案谢谢啦!这对我非常重要!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-29 11:47:53 | 显示全部楼层
永远不要试图理解递归代码内部发生了什么

这个“行6”是
第二步 执行 ‘行4’else::
执行 ‘行5’, 第一次递归开始,((n-1), a, c, b)回到函数最初代入(3, a='A', b='B', c='C'),得出参数为(2, 'A', 'C', 'B'),【!注意: 此时‘行1 ’(3, a='A', b='B', c='C')在 ‘行5’ 递归回到函数最初运行后已改变为(2, a='A', b='C', c='B')】
执行 ‘行2 - 3’ ,n != 1, ‘行2 - 3’ 越过
执行else:
执行 ‘行5’,将((n-1), a, c, b)代入(2, a='A', b='C', c='B'),得出参数为(1, 'A', 'B', 'C') ,继续执行 ‘行2 - 3’,n == 1 返回输出:(a, "->", c)代入(1, 'A', 'B', 'C') ,即 A -> C
回到 ’ 行5‘,继续执行 ‘行6’ ,将(a, "->", c)代入move函数(2, a='A', b='C', c='B')并输出,即 A -> B
执行 ’行7‘,将( (n-1), b, a, c)代入(2, a='A', b='C', c='B')得出参数为(1, 'C', 'A', 'B'),继续执行 ‘行2 - 3’,n == 1 返回输出:(a, "->", c)代入(1, 'C', 'A', 'B') ,即 C -> B
中第一个“行5”,即
执行 ‘行5’, 第一次递归开始,((n-1), a, c, b)回到函数最初代入(3, a='A', b='B', c='C'),得出参数为(2, 'A', 'C', 'B'),【!注意: 此时‘行1 ’(3, a='A', b='B', c='C')在 ‘行5’ 递归回到函数最初运行后已改变为(2, a='A', b='C', c='B')】
执行后执行的

再次重申:永远不要去理解递归里面发生了什么,你只需要搞懂思路即可
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-25 22:08

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表