汉诺塔问题(递归栈)
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 }
方法二:使用栈来实现
这样思考,一共有的动作一共就四种: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 }
以上是关于汉诺塔问题(递归栈)的主要内容,如果未能解决你的问题,请参考以下文章
汉诺塔(Tower of Hanoi)问题的求解——利用栈与递归