暴力递归——汉诺塔问题

简介: 暴力递归——汉诺塔问题

打印n层汉诺塔从最左边移动到最右边的全部过程

暴力递归就是尝试

1)把问题转化为规模缩小了的同类问题的子问题

2)有明确的不需要继续进行递归的条件(base case)

3)有当得到了子问题的结果之后的决策过程

4)不记录每一个子问题的解

补充一点,如果记录每一个子问题的解就是动态规划,后续文章会讲到。

递归方法

假设有3跟柱子,左、中、右,我们细分为如下三个步骤:

1)将1~N-1层圆盘从左 -> 中(大问题,需要继续划分为小问题)

2)将第N层圆盘从左 -> 右(base case)

3)将1~N-1层圆盘从中 -> 右(大问题,需要继续划分为小问题)

递归方法改进版

如果我们忘记柱子的左中右,将三根柱子标记为from、to、other。我们实现的是,将所有的圆盘(一共N层)从from -> to,同样细分为3个步骤:

1)将1~N-1层圆盘从from -> other(大问题,需要继续划分为小问题)

2)将第N层圆盘从from -> to(base case,可以直接打印)

3)将1~N-1层圆盘从other -> to(大问题,需要继续划分为小问题)

貌似没什么改进,因为还是细分这三步,同样要递归,但关键在于忘掉柱子的左中右顺序,只需要三个变量,代码可以少很多。

总结

汉诺塔问题还有非递归的解法,因为任何递归都可以改成非递归,只需要自己设计压栈。但是博主个人认为汉诺塔的递归方法比非递归更好容易理解和实现,非递归自己去设计压栈还比较麻烦,博主目前也还没弄懂,所以就只附上代码了。后面如果搞懂了在补充吧,😄

附上完整代码

package com.harrison.class12;
import java.util.Stack;
public class Code01_Hanoi {
  public static void leftToRight(int n) {
    if(n==1) {
      System.out.println("move 1 from left to right");
      return ;
    }
    leftToMid(n-1);
    System.out.println("move "+ n +" from left to right");
    midToRight(n-1);
  }
  public 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);
  }
  public 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);
  }
  public 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");
    rightToLeft(n-1);
  }
  public static void rightToLeft(int n) {
    if(n==1) {
      System.out.println("move 1 from right to left");
      return ;
    }
    rightToMid(n-1);
    System.out.println("move "+ n +" from right to left");
    midToLeft(n);
  }
  public 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);
  }
  public static void hanoi1(int n) {
    leftToRight(n);
  }
  public static void f(int n,String from,String to,String other) {
    if(n==1) {
      System.out.println("move 1 from "+ from + " to " + to);
    }else {
      f(n-1, from, other, to);
      System.out.println("move " + n + " from " +from +" to "+to);
      f(n-1, other,to,from);
    }
  }
  public static void hanoi2(int n) {
    if(n>0) {
      f(n, "left", "right", "mid");
    }
  }
  public static class Record {
    public boolean finish1;
    public int base;
    public String from;
    public String to;
    public String other;
    public Record(boolean f1, int b, String f, String t, String o) {
      finish1 = false;
      base = b;
      from = f;
      to = t;
      other = o;
    }
  }
  public static void hanoi3(int N) {
    if (N < 1) {
      return;
    }
    Stack<Record> stack = new Stack<>();
    stack.add(new Record(false, N, "left", "right", "mid"));
    while (!stack.isEmpty()) {
      Record cur = stack.pop();
      if (cur.base == 1) {
        System.out.println("Move 1 from " + cur.from + " to " + cur.to);
        if (!stack.isEmpty()) {
          stack.peek().finish1 = true;
        }
      } else {
        if (!cur.finish1) {
          stack.push(cur);
          stack.push(new Record(false, cur.base - 1, cur.from, cur.other, cur.to));
        } else {
          System.out.println("Move " + cur.base + " from " + cur.from + " to " + cur.to);
          stack.push(new Record(false, cur.base - 1, cur.other, cur.to, cur.from));
        }
      }
    }
  }
  public static void main(String[] args) {
    int n=3;
    hanoi1(n);
    System.out.println("=======================");
    hanoi2(n);
    System.out.println("=======================");
    hanoi3(n);
    System.out.println("=======================");
  }
}


相关文章
汉诺塔 递归问题
汉诺塔 递归问题
85 0
递归问题的实际运用:汉诺塔问题
递归问题的实际运用:汉诺塔问题
120 0
递归问题的实际运用:汉诺塔问题
【递归问题】——汉诺塔
【递归问题】——汉诺塔
230 0
|
算法 Java
【递归与回溯算法】汉诺塔与八皇后问题详解
文章目录 1 汉诺塔问题 1.1 汉诺塔问题概述 1.2 思路分析 1.3 代码实现(Java) 1.4 结果验证 2 八皇后问题 2.1 八皇后问题概述 2.2 思路分析 2.2.1 问题划分与分析 2.2.2 涉及到的数据结构分析 2.2.3 上下对角线与行列的关系 2.3 代码实现(Java) 2.4 结果验证
【递归与回溯算法】汉诺塔与八皇后问题详解
递归—汉诺塔
汉诺塔是经典递归问题:相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
204 0
递归—汉诺塔
汉诺塔问题(递归版)
汉诺塔问题(递归版)
201 0
C#中汉诺塔问题的递归解法
百度测试部2015年10月份的面试题之——汉诺塔。 汉诺塔就是将一摞盘子从一个塔转移到另一个塔的游戏,中间有一个用来过度盘子的辅助塔。 百度百科在此。 游戏试玩在此。 用递归的思想解决汉诺塔问题就是分为两种情况: 第一种情况是只有一个盘子的情况,也就是最基本的情况,这种情况下,直接将该盘子从原始塔转移到目标塔即可胜利; 第二种情况是右n个盘子的情况,也就是普遍情况,这种情况下,要将除了最底下的那个盘子以外的(n-1)个盘子从原始塔转移到辅助塔,再把最底下的那个盘子(第n个盘子)从原始塔转移到目标塔,最后将辅助塔的(n-1)个盘子从辅助塔转移到目标塔。
1847 0
|
机器学习/深度学习 缓存 机器人
从暴力递归到动态规划,记忆化搜索
从暴力递归到动态规划,记忆化搜索
从暴力递归到动态规划,记忆化搜索