算法笔记:使用栈实现汉诺塔(Hanoi)经典算法
来源:互联网 发布:四方麻将 河南软件 编辑:程序博客网 时间:2024/06/10 18:33
汉诺塔(Hanoi)算法,应该是每一个程序员都会学习到的递推算法之一,汉诺塔是一个很著名的智力题,但是这里就不科普它的由来了,我们直接进入正题。
如上图,假设A棒有五个原盘,依次移动,每次移动一块,小的永远只能在上面,最终移动到C棒上,如何用算法实现呢?
从这里移动的逻辑我们很容易发现,A帮不就像一个栈吗,栈顶必须先出,网上看过很多汉诺塔算法,很少涉及到用栈实现,的确,算法拿出来了,用什么都一样,在我学习的时候,教材上是用的char,直接模拟推算,没用真正移动数据实现真正的Hanoi思想,所以,琢磨了一会,写了一个用栈实现的算法。
首先,既然是栈,为了方便跟踪,写了一个自己的MyStack包装了一下Java的Stack,贴上代码:
class MyStack{ private String name; private Stack<Integer> data; public MyStack(String name){ this.name=name; data=new Stack<>(); } public String getName(){ return this.name; } public void push(int data){ if(!this.data.isEmpty()&&this.data.peek()<data){ System.out.println("出错"); } this.data.push(data); } public int peek(){ return data.peek(); } public int pop(){ return data.pop(); } public int size(){ return data.size(); } public boolean isEmpty(){ return data.isEmpty(); }}
然后就是Hanoi递推的实现,还是贴上图片
我们要按照Hanoi的逻辑将原盘从A棒移动到C棒,那么,就必须以B棒作为媒介,
最大的必须在最下面,所以,我们必须把上面4个圆盘先移动到B棒上。
但是又看,上面4个,要想把第四个移动到B棒,就得用C棒暂时当媒介,先把上面3个移动到C棒,以此类推,知道只有最后一个的时候,就可以直接移动了,所以,我们要做的就是想出一个算法,递推到只剩一个圆盘,然后慢慢回栈,到第二,第三,第四,最后第五。
先贴上代码:
public static void hanoi(int size,MyStack a,MyStack b,MyStack c){ if(size==1){ c.push(a.pop()); }else{ int n=b.size(); hanoi(size-1,a,c,b); c.push(a.pop()); hanoi(b.size()-n,b,a,c); } }
首先解释参数中的size,因为栈无法在不取出元素的情况下递减长度,所以增加了参数size作为栈的圆盘指针,限定只能移动size个圆盘。
所以,当size==1的时候,就是只剩下一个圆盘,那么就顺理成章的直接移动到C棒了,不必在意此时的C棒回栈后是B棒还是A棒,那不是此时递归该担心的事情。
在算法中,如果size!=1,那么说明我们需要一个作为媒介,让size-1个圆盘先暂时放到媒介上,然后将第size个圆盘放过去,所以,我们需要进行一次递归,将第size-1个上面的圆盘重新进行计算该存放的位置,计算完成后,然后放入第size个圆盘到C帮,然后再将媒介B棒中的圆盘又以A棒为媒介,以此方式放入C盘。
至于为什么要在递归前缓存一次B棒的size,因为进入递归前不知道B棒是否有数据,说不定此次计算正是上一次的递归呢,不知道后面的方法B棒会是怎样的存在,不知道会进入多少次递归,假设B棒在进入第一次递归前长度为2,递归完后,长度为5,第二次递归时,如果不限制size长度,直接使用B棒的size,那么,除了第一次递归时增加的3个数据,还会把原本的2个数据一起计算进去,博主就在这个坑绕了一些时间,最后跟踪了一下才明白这个。
文字有点多,最后贴上完整代码:
public class Hanoi { private static int m=1; private static MyStack a=new MyStack("A"); private static MyStack b=new MyStack("B"); private static MyStack c=new MyStack("C"); public static void main(String[] args) { for(int i=5;i>0;i--){ a.push(i); } hanoi(a.size(),a,b,c); print(c); } public static void hanoi(int size,MyStack a,MyStack b,MyStack c){ if(size==1){ System.out.println("第"+m+++"步,从"+a.getName()+"移动了 "+a.peek()+"到了"+c.getName()); c.push(a.pop()); }else{ int n=b.size(); hanoi(size-1,a,c,b); System.out.println("第"+m+++"步,从"+a.getName()+"移动了 "+a.peek()+"到了"+c.getName()); c.push(a.pop()); hanoi(b.size()-n,b,a,c); } } public static void print(MyStack temp){ System.out.println("size:"+temp.size()); for(int i=0,n=temp.size();i<n;i++){ System.out.print(temp.pop()+" "); } System.out.println(); }}class MyStack{ private String name; private Stack<Integer> data; public MyStack(String name){ this.name=name; data=new Stack<>(); } public String getName(){ return this.name; } public void push(int data){ if(!this.data.isEmpty()&&this.data.peek()<data){ System.out.println("出错"); } this.data.push(data); } public int peek(){ return data.peek(); } public int pop(){ return data.pop(); } public int size(){ return data.size(); } public boolean isEmpty(){ return data.isEmpty(); }}
核心算法只有那一段,其他是我为了方便跟踪增加的,各位在测试的时候可以选择性删除。
- 算法笔记:使用栈实现汉诺塔(Hanoi)经典算法
- 汉诺塔(hanoi)算法实现
- Hanoi的实现算法
- hanoi塔经典递归算法
- 汉诺塔(Hanoi)递归算法笔记记录
- 汉诺塔(Hanoi)问题递归算法实现
- 递归算法-->汉诺塔hanoi
- 经典算法系列---hanoi塔问题
- Hanoi算法
- C语言-递归算法以及经典递归(Hanoi)
- 关于汉诺塔hanoi算法的自我感受
- 算法——汉诺塔(Hanoi)
- 趣味算法-Hanoi
- Hanoi塔算法
- hanoi递归算法
- Hanoi递归算法
- 算法训练 Hanoi问题
- Hanoi塔算法分析
- IP网络协议
- vuejs组件之slot内容分发实例详解
- 5. Longest Palindromic Substring
- BZOJ 2210: Pku1379 Run Away 模拟退火
- 杭电1001 Sum Problem
- 算法笔记:使用栈实现汉诺塔(Hanoi)经典算法
- 垃圾收集与分配策略——(三)HotSpot的算法实现
- Java注解
- QWT的配置和使用(1)
- java递归浅析合并排序
- 杭电1002 A + B Problem II
- 机器学习之旅:数据预处理的对象-数据
- C++常成员函数和常对象、对象指针和对象引用
- C++11基础-----std::function & std::bind