zoukankan      html  css  js  c++  java
  • 汉诺塔的递归学习,以及一些其中的一些规律

      啥也不废话进入正题:

      首先是经典的解法,即递归,过程大概如下图

      实现的代码如下:

        int steps = 0;
        int [] sData = new int[]{1,2,3,4,5,6};
        int [] hData = new int[sData.length];
        int [] tData = new int[sData.length];
        @Test
        public void testHanoi(){
            long start = new Date().getTime();
            hanoi(sData.length,sData,hData,tData);
            long end = new Date().getTime();
            System.out.println(Arrays.toString(tData));
            System.out.println("共走了 :" + steps + "步。" + "花费时间:"+(end-start));
        }
    
            /**
         * 
         * @param n
         * @param sData : 待移动的集合
         * @param hData : 辅助空间 
         * @param tData : 目标集合
         */
        // n:编号,x:待移动的集合 y:辅助空间 z:目标集合
        private void hanoi(int n, int[] sData, int[] hData, int[] tData) {
            if(n == 1){
                move(1,sData,tData);
            }else{
                hanoi(n-1,sData,tData,hData);
                move(n , sData , tData );
                hanoi(n-1,hData,sData,tData);
            }
            
        }
        
        private void move(int i, int[] sData, int[] tData) {
            tData[i-1] = sData[i-1];
            sData[i-1] = 0;
            steps++;
            /*System.out.print("source:"+Arrays.toString(this.sData) + "   target:"+Arrays.toString(this.tData) +"   help:");
            System.out.print(Arrays.toString(this.hData)+"   ");
            System.out.println("将第"+i+"个方块从 "+judgeName(sData)+" 移动到 "+judgeName(tData));*/
        }
    
        String judgeName(int []Data){
            if(Data == this.sData){
                return "source";
            }else if(Data == this.tData){
                return "target";
            }else if(Data == this.hData){
                return "help";
            }
            return "";
        }
        

      由于有强迫症,硬是要用脑子去递归这块代码,结果大脑溢出了。。。,于是跟着debug跟了一下,算是稍微有点点收获(自己安慰自己),不管了,根据代码的流程来总结总结是到底怎么换的。

      

                         上级递归不断重复下级递归,每级递归都要走到最内层(最深层,方法栈最上层)递归才可以返回

      这里特别要关注的是,不同角色的空间,传到下一级递归时候角色的转变 , 所以返回上级递归,要根据入参规则转换一下 , 不然还是很难理解返回的时候,参数的变换是什么意思,比如说上图 n=3时候的递归场景,返回到 n=4的递归场景,target和help要交换一下角色,才是这级递归对应的角色(因为入参的时候,是交换角色入参的)。

      其实递归过程中最绕的就是这些参数角色之间的转换,但是真正存储的空间和含义(最外层递归定义的含义)只有一个,在调用自己的时候,可能会产生角色交换,所以导致大脑溢出。除了要搞清楚最原始定义的空间是怎么变化的,其他的还是很好理解的,递归嘛,感觉像是一种继承性,像是不断的 子承父业 子承父业 子承父业,直到断子绝孙了,你就可以返回,一直返回到祖宗十八代,就玩完了。

    一下介绍一下非递归的算法的思想,很固定的套路

    非递归算法描述如下:

    首先容易证明,当盘子的个数为n时,移动的次数应等于2^n - 1。

    一位美国学者发现一种出人意料的方法,只要轮流进行两步操作就可以了。

    首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子A上。

    根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C;

    若n为奇数,按顺时针方向依次摆放 A C B。

    (1)按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;

    若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A。

    (2)接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。

    即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘

    这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。

    (3)反复进行(1)(2)操作,最后就能按规定完成汉诺塔的移动。

    啥时候也能有苹果光临光临咱们的脑瓜子呀。

    实现代码:

      
      int steps = 0 ;
      @Test
    public void testHanoi2(){ LinkedList<Integer> source = new LinkedList<Integer>(); LinkedList<Integer> target = new LinkedList<Integer>(); LinkedList<Integer>help = new LinkedList<Integer>(); // 若source中有 偶数个元素 , 那么 , 最终全部转换到第三个容器 ; 为奇数的话,全部转换到第二个容器 LinkedList<Integer> [] datas = new LinkedList[3]; datas[0] = source; datas[1] = help; datas[2] = target; for(int i=5 ; i>0 ; i--){ source.push(i); } int count = source.size(); for(int j=0 ; target.size() != count ;j++){ int index = j%3; // 这个会是最终存储所有方块的容器的索引 int nexIndex =(index+1)%3 ; int otherIndex = (nexIndex+1)%3; datas[nexIndex].push(datas[index].pop()); steps++; if(datas[nexIndex].size() == count){ break; } if(datas[otherIndex].isEmpty() ){ datas[otherIndex].push(datas[index].pop()); }else if(datas[index].isEmpty()){ datas[index].push(datas[otherIndex].pop()); }else if(datas[index].peek()>datas[otherIndex].peek()){ datas[index].push(datas[otherIndex].pop()); }else if(datas[otherIndex].peek()>datas[index].peek()){ datas[otherIndex].push(datas[index].pop()); } steps++; } System.out.println(target); System.out.println(source); System.out.println(help); System.out.println("共花费:"+steps); }

    以上纯属个人观点,如有不对,还请大佬鞭策,谢谢大佬们

  • 相关阅读:
    基于简单工厂模式的计算器程序
    Android网络请求之OkHttp框架
    利用Volley框架实现手机号归属地查询
    Android网络请求之HttpURLConnection/HttpClient
    HDU4001 最长上升子序列
    xml易混淆的几组属性
    HDU2444 二分图
    HDU2018 斐波那契
    HDU1427 速算24点
    工厂模式
  • 原文地址:https://www.cnblogs.com/liujiaa/p/7745805.html
Copyright © 2011-2022 走看看