【Python|汉诺塔问题和代码参数调用逻辑和流程图详解】

汉诺塔问题:
相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如图1)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
来源于百度百科

————————————————

解题过程:
首先我们要知道,无论有多少个圆盘,最底下的圆盘 n 想要从起始柱移动到目标柱上,得先把除了 n 以外的圆盘移动到 移动到辅助柱上

也就是说,如果有 n 个圆盘,我们想把第 n 个移到 C 上,得先把上面的 n-1 个移动到 B 柱,然后才能把第 n 个圆盘移动到C上

那么问题又来了,想把 n 上面的 n-1 个圆盘移动到 B 上,我们又需要把第 n-1 个圆盘上面的 n-2 个圆盘先移到 C 上,才能把第 n-1 个移到 B 上


'''
不要总想着数学公式里面发现什么,跳出这个思维,问问自己这个函数干什么用的。前面教程中讲解,
告诉你函数是干什么的之后,就没有再深究函数里面的内容,而是按照函数的功能,自我调用。
汉诺塔函数的功能就是把所有(n个)盘子从a柱移c柱,在此之前需要先将最底层的一个盘子之外的所有盘子,
也就是n-1个盘子从a柱移到b柱,a柱最底下的那个盘子才能移c柱。现在,将n-1个盘子看成另一个所有盘子,
调用汉诺塔函数,将所有n-1个盘子从b柱移动到c柱,就完事了。
'''


def hanoi(n, a, b, c):
    if n == 1:
        print('第' + str(n) + '个圆盘从' + a + ', -->', c)
    else:
        hanoi(n - 1, a, c, b)  # hanoi(2,'A','C','B')
        print('第' + str(n) + '个圆盘从' + a + ', -->', c)
        hanoi(n - 1, b, a, c)


# 调用
# hanoi(5, 'A', 'B', 'C')

'''
对函数执行过程进行说明讲解一下
当n=3时 函数执行过程
        hanoi(n - 1, a, c, b)  # hanoi(2,'A','C','B')
        print('第' + str(n) + '个圆盘从' + a + ', -->', c)  //当n=3时,打印A--->C
        hanoi(n - 1, b, a, c)  # hanoi(2,'B','A','C')
        
        其中函数hanoi(2,'A','C','B') 递归调用自己函数 此时形参a='A' b='C' c='B'
         hanoi(1, a, c, b)   //打印A--->C
         print('第' + str(n) + '个圆盘从' + a + ', -->', c)  //打印A--->B
         hanoi(1, b, a, c)    //打印C--->B
        
        其中函数hanoi(2,'B','A','C') 递归调用自己函数 此时形参a='B' b='A' c='C' 将B柱子上的2个圆盘借助辅助A柱子移动到C柱子
         hanoi(1, a, c, b)   //打印B--->A
         print('第' + str(n) + '个圆盘从' + a + ', -->', c)  //打印B--->C
         hanoi(1, b, a, c)    //打印A--->C
        
'''

个人画图理解汉诺塔
processon汉诺塔流程图

<think>我们正在讨论递归算法。根据引用内容,递归是一种通过函数自调用解决问题的编程技巧,将复杂问题分解为结构相似的子问题。递归包含递推(分解问题回归(合并结果)两个阶段。 下面我将详细解释递归的原理、实现方法应用场景,并给出代码示例。</think>### 递归算法详解 #### 一、递归的基本原理 递归是一种**通过函数自调用解决问题**的编程技术,其核心思想是将复杂问题分解为多个结构相似的子问题。递归算法包含两个关键阶段: 1. **递推阶段(问题分解)** - 将原问题分解为规模更小的同类子问题 - 持续分解直到达到**基线条件(Base Case)**(可直接求解的最小问题) $$ \text{问题} \rightarrow \text{子问题} \rightarrow \text{更小的子问题} \rightarrow \cdots \rightarrow \text{基线条件} $$ 2. **回归阶段(结果合并)** - 从基线条件开始逐层返回结果 - 组合子问题的解形成原问题的解 $$ \text{基线解} \rightarrow \text{子问题解} \rightarrow \cdots \rightarrow \text{原问题解} $$ **递归三要素**: 1. **基线条件(Base Case)**:递归终止条件,防止无限循环 2. **递归步骤(Recursive Step)**:将问题分解为更小的同类子问题 3. **收敛性(Convergence)**:每次递归都向基线条件靠近 > 递归的本质是数学归纳法在编程中的应用:证明基线条件成立,并证明若$n=k$成立则$n=k+1$也成立[^1]。 #### 二、递归实现方法(Python示例) ##### 1. 阶乘计算 ```python def factorial(n): # 基线条件 if n == 0: return 1 # 递归步骤 return n * factorial(n-1) print(factorial(5)) # 输出: 120 ``` **执行过程**: ``` factorial(5) 5 * factorial(4) 5 * (4 * factorial(3)) 5 * (4 * (3 * factorial(2))) 5 * (4 * (3 * (2 * factorial(1)))) 5 * (4 * (3 * (2 * (1 * factorial(0))))) 5 * (4 * (3 * (2 * (1 * 1)))) = 120 ``` ##### 2. 斐波那契数列 ```python def fibonacci(n): # 基线条件 if n <= 1: return n # 递归步骤(分解为两个子问题) return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(6)) # 输出: 8 (序列: 0,1,1,2,3,5,8) ``` ##### 3. 汉诺塔问题 ```python def hanoi(n, source, target, auxiliary): if n > 0: # 将n-1个盘子移到辅助柱 hanoi(n-1, source, auxiliary, target) # 移动最底层的盘子 print(f"移动盘子 {n} 从 {source} 到 {target}") # 将n-1个盘子移到目标柱 hanoi(n-1, auxiliary, target, source) hanoi(3, 'A', 'C', 'B') ``` **输出**: ``` 移动盘子 1 从 A 到 C 移动盘子 2 从 A 到 B 移动盘子 1 从 C 到 B 移动盘子 3 从 A 到 C 移动盘子 1 从 B 到 A 移动盘子 2 从 B 到 C 移动盘子 1 从 A 到 C ``` #### 三、递归的应用场景 | 应用领域 | 典型示例 | 特点 | |---------|---------|------| | **数学计算** | 阶乘、斐波那契数列 | 天然递归定义 | | **数据结构** | 树/图的遍历(DFS) | 嵌套结构适合递归 | | **分治算法** | 归并排序、快速排序 | 问题可分解为子问题 | | **回溯算法** | 八皇后问题、数独 | 需要尝试所有可能路径 | | **动态规划** | 背包问题、最短路径 | 重叠子问题优化 | | **编译器设计** | 语法分析(AST构建) | 处理嵌套语法结构 | #### 四、递归的优化策略 1. **尾递归优化** 将递归调用放在函数最后一步,编译器可优化为迭代: ```python def factorial_tail(n, acc=1): if n == 0: return acc return factorial_tail(n-1, acc*n) # 尾递归 ``` 2. **备忘录模式(Memoization)** 存储已计算结果避免重复计算: ```python memo = {} def fibonacci_memo(n): if n in memo: return memo[n] if n <= 1: return n memo[n] = fibonacci_memo(n-1) + fibonacci_memo(n-2) return memo[n] ``` 3. **迭代替代** 对于深度大的递归,改用循环: ```python def factorial_iter(n): result = 1 for i in range(1, n+1): result *= i return result ``` 4. **尾递归消除**(手动转换为迭代): ```python def factorial_iter_tail(n): acc = 1 while n > 0: acc *= n n -= 1 return acc ``` #### 五、递归的优缺点分析 **优点**: - 代码简洁优雅,更接近数学定义 - 简化复杂问题的解决方案 - 天然适合处理嵌套结构(树/图) **缺点**: - 栈溢出风险(深度过大时) - 重复计算问题(如朴素斐波那契) - 调试难度较高 - 通常比迭代版本效率低 > 递归深度限制可通过`sys.setrecursionlimit()`调整,但需谨慎使用[^3]。 #### 六、递归与迭代的对比 | 特性 | 递归 | 迭代 | |------|------|------| | **实现方式** | 函数自调用 | 循环结构 | | **内存使用** | 栈空间$O(n)$ | 堆空间$O(1)$ | | **代码可读性** | 问题定义清晰 | 执行流程明确 | | **适用问题** | 分治/回溯问题 | 线性处理问题 | | **性能** | 函数调用开销大 | 通常更高效 | **选择原则**: - 问题天然递归定义 → 优先递归 - 性能关键且深度大 → 改用迭代 - 需要尝试所有路径 → 递归+回溯 递归是计算机科学的基石之一,掌握其原理能显著提升算法设计能力。在实际应用中,常结合备忘录优化尾递归转换来平衡可读性与性能[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值