从 最具启发性的汉诺塔问题开始 聊递归

本文篇幅较长,建议仔细耐心看完,相信会有极大的收获。

一、最具启发性的汉诺塔问题

1、汉诺塔问题描述

有三根杆子A,B,C。A杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:每次只能移动一个圆盘;大盘不能叠在小盘上面。

问:最少要移动多少次?并打印每次移动的情况。

2、从最初开始

我们的目标是将1、2、3圆盘从左杆移到右杆
在这里插入图片描述

可以拆解为以下三步

1)(大步)将1、2圆盘从左移到中杆

2)将3圆盘从左移到右杆

3)(大步)将1、2圆盘从中移到右杆
在这里插入图片描述

代码如下:

/**
 * @author Java和算法学习:周一
 */
public static void leftToRight(int n) {
   
    if (n == 1) {
    // base case
        System.out.println("Move 1 from left to right");
        return;
    }
    // 1、1到n-1个圆盘从左到中
    leftToMid(n - 1);
    // 2、从左到右
    System.out.println("Move " + n + " from left to right");
    // 3、1到n-1个圆盘从中到右
    midToRight(n - 1);
}

整个左到右方法,你会发现第一大步依赖左到中子方法,第三大步依赖中到右子方法,然后你去补起左到中方法、中到右方法;此时又会发现左到中依赖左到右、右到中方法,中到右依赖中到左、左到右方法……

/**
 * @author Java和算法学习:周一
 */
private static void leftToMid(int n) {
   
    if (n == 1) {
   
        System.out.println("Move 1 from left to mid");
        return;
    }
    leftToRight(n - 1);
    System.out.println("Move " + n + " from left to mid");
    rightToMid(n - 1);
}

private static void midToRight(int n) {
   
    if (n == 1) {
   
        System.out.println("Move 1 from mid to right");
        return;
    }
    midToLeft(n - 1);
    System.out.println("Move " + n + " from mid to right");
    leftToRight(n - 1);
}

private static void rightToMid(int n) {
   
    if (n == 1) {
   
        System.out.println("Move 1 from right to mid");
        return;
    }
    rightToLeft(n - 1);
    System.out.println("Move " + n + " from right to mid");
    leftToMid(n - 1);
}

private static void midToLeft(int n) {
   
    if (n == 1) {
   
        System.out.println("Move 1 from mid to left");
        return;
    }
    midToRight(n - 1);
    System.out.println("Move " + n + " from mid to left");
    rightToLef
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
汉诺塔问题的非递归实现可以借助堆栈以循环方式求解。具体实现方法如下: 1.将起始柱、目标柱、借助柱的状态压入栈中。 2.当栈不为空,取出栈顶状态,如果当前状态为最终状态,则输出结果并结束程序。 3.否则,根据当前状态,计算出下一步的状态,并将其压入栈中。 4.重复步骤2和3,直到找到最终状态为止。 具体实现过程中,需要注意以下几点: 1.状态的表示可以使用一个结构体,包含起始柱、目标柱、借助柱的编号以及当前移动的盘子数。 2.计算下一步状态,需要根据当前状态的盘子数和柱子的编号来确定下一步移动的盘子和目标柱。 3.在压入栈中,需要按照一定的顺序将状态压入,以保证栈顶状态是当前最优状态。 下面是一个简单的C++实现代码,仅供参考: ``` #include <iostream> #include <stack> using namespace std; struct State { int n; // 当前移动的盘子数 int from, to, via; // 起始柱、目标柱、借助柱的编号 }; void move(int n, int from, int to) { cout << "Move disk " << n << " from " << from << " to " << to << endl; } void hanoi(int n, int from, int to, int via) { stack<State> s; s.push({n, from, to, via}); while (!s.empty()) { State cur = s.top(); s.pop(); if (cur.n == 1) { move(1, cur.from, cur.to); } else { s.push({cur.n - 1, cur.via, cur.to, cur.from}); s.push({1, cur.from, cur.to, cur.via}); s.push({cur.n - 1, cur.from, cur.via, cur.to}); } } } int main() { int n = 3; hanoi(n, 1, 3, 2); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值