汉诺塔问题(递归栈)

Posted futurehau

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汉诺塔问题(递归栈)相关的知识,希望对你有一定的参考价值。

修改一下汉诺塔的游戏规则,现在不能直接从左边走到右边,也不能直接右边走到左边。

方法一:递归实现

现在分析一下,比如左边有1~n,那么移动最后一个的情况,就是:

1.1-n-1从左边移动到右边

2.n从左边移动到中间

3.1-n-1从右边移动到左边

4.n从中间移动到右边

5.1-n-1从左边移动到右边

那么,假如我有这样一个f(range,from,to)那么我需要求解的就是f(n,lrft,right),原子情况就是从只有一个数的时候,直接左边中间右边即可。

技术分享
 1  public static int process(int num, String from, String to) {
 2         if (num == 1) {
 3             System.out.println("move 1 from " + from +" to middle");
 4             System.out.println("move 1 from middle to " + to);
 5             return 2;
 6         }
 7         else {
 8             int p1 = process(num - 1, from, to);
 9             System.out.println("move "+ num + " from " + from +" to middle");
10             int p2 = process(num - 1, to, from);
11             System.out.println("move "+ num + " from middle to " + to);
12             int p3 = process(num - 1, from, to);
13             return  p1 + p2 + p3 +2;
14         }
15     }
View Code

方法二:使用栈来实现

这样思考,一共有的动作一共就四种:L2M M2L M2R R2M

在任何一个时刻,要想最少移动次数,并且满足小压大原则,则只有一种情况能够得到满足。

证明如下:

假如上一个动作是L2M,那么不可能L2M(小压大),也不可能M2L(最优),那么剩下M2R和R2M,就一定有一种情况会得到满足。其他情况同理。

所以使用三个栈分别记录左中右的数,然后每次检测出满足条件的那个来继续即可。由于每个都会去除每个栈的栈顶元素来进行比较,所以为了避免判断是否为空,就首先在每个栈的栈顶压入最大值以最为保障。结束的条件就是最右边的栈中元素个数为总的元素个数。

技术分享
 1  public static enum Action {
 2         No,L2M, M2L,M2R,R2M
 3     }
 4     public static int hanoiProblem2(int num) {
 5         Stack<Integer> ls = new Stack<Integer>();
 6         Stack<Integer> ms = new Stack<Integer>();
 7         Stack<Integer> rs = new Stack<Integer>();
 8         ls.push(Integer.MAX_VALUE);
 9         ms.push(Integer.MAX_VALUE);
10         rs.push(Integer.MAX_VALUE);
11         for (int i = num; i > 0; i--) {
12             ls.push(i);
13         }
14         Action[] preAction = {Action.No};
15         int step = 0;
16         while (rs.size() != num + 1) {
17             step += fStack2Stack(preAction,Action.M2L,Action.L2M,ls,ms);
18             step += fStack2Stack(preAction,Action.L2M,Action.M2L,ms,ls);
19             step += fStack2Stack(preAction,Action.R2M,Action.M2R,ms,rs);
20             step += fStack2Stack(preAction,Action.M2R,Action.R2M,rs,ms);
21         }
22         return step;
23     }
24     public static int fStack2Stack(Action[] preAction, Action noAction, Action curAction,
25                                    Stack<Integer> fStack, Stack<Integer> tStack) {
26         if (preAction[0] == noAction || fStack.peek() >= tStack.peek()) {
27             return 0;
28         }
29         preAction[0] = curAction;
30         tStack.push(fStack.pop());
31         return 1;
32     }
View Code

 

以上是关于汉诺塔问题(递归栈)的主要内容,如果未能解决你的问题,请参考以下文章

汉诺塔(Tower of Hanoi)问题的求解——利用栈与递归

汉诺塔(Tower of Hanoi) 递归代码实现 c语言(顺序栈实现)

汉诺塔问题(递归栈)

栈实现递归实现汉诺塔问题

数据结构--汉诺塔--借助栈实现非递归---Java

面试题 08.06. 汉诺塔问题(非递归实现汉诺塔问题)