生活随笔
收集整理的這篇文章主要介紹了
汉诺塔非递归算法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
這兩天講《Web程序設計》,用JavaScript寫了個漢諾塔的非遞歸算法,覺得有點意思,放在這里吧!
傳統的遞歸算法:?
<html?xmlns="http://www.w3.org/1999/xhtml">? <head>? <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>? <title>Hanoi?Tower?(Recursive?algorithm)?-?漢諾塔(遞歸算法)</title>? <style?type="text/css">? i?{ ?????color:?#0000ff; ?} ?P?{ ?????text-align:?center; ?} ? </style>? <script?type="text/javascript">? var?step=0; ? function?MoveOnePlate(n,?loca1,?loca2) ?{ ? ????document.write("第"?+?++step?+?"步:移動第<i>"?+?n?+?"</i>個盤子,從"?+?loca1?+?"到"?+?loca2?+?"<br?/>"); ? } ??function?MovePlates(n,?s,?m,?d) ?{ ? ????if(n==1) ? ??????MoveOnePlate(n,?s,?d); ?????else ?????{ ?????????MovePlates(n-1,?s,?d,?m); ?????????MoveOnePlate(n,?s,?d); ?????????MovePlates(n-1,?m,?s,?d); ?????} ?} ? </script>? </head>? ? <body>? <p>Hanoi?Tower?(Recursive?algorithm)?-?漢諾塔(遞歸算法)<br?/>Mengliao?Software?Studio(Baiyu)?-?夢遼軟件工作室(白宇)<br?/>? Copyright?2011,?All?right?reserved.?-?版權所有(C)?2011<br?/>2011.03.31</p>? <script?type="text/javascript">? ????n=parseInt(prompt("請輸入盤子的數量:",?3),?10); ? ????if?(isNaN(n)?||?n<1?||?n>16) ? ????{ ?????????alert("請輸入介于1到16的自然數!"); ?????????location.reload(); ?????} ?????else ?????{ ? ????????document.write("共"?+?n?+?"個盤子,需移動"?+?(Math.pow(2,?n)-1)?+?"步:<br?/><br?/>"); ? ????????MovePlates(n,?"<i>源點</i>",?"<i>臨時</i>",?"<i>目標</i>"); ? ????} ? </script>? </body>? </html>? 這個遞歸算法就不詳細說了,核心代碼只有5、6行。
下面是非遞歸算法:?
<html?xmlns="http://www.w3.org/1999/xhtml">? <head>? <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>? <title>Hanoi?Tower?(Non-recursive?algorithm)?-?漢諾塔(非遞歸算法)</title>? <style?type="text/css">? i?{ ?????color:?#ff0000; ?} ?p?{ ?????text-align:?center; ?} ? </style>? <!-- ?漢諾塔非遞歸算法: ?(1)、若問題規模n為偶數,按順時針方向依次擺放s,?m,?d為環,若n為奇數,則為s,?d,?m; ?(2)、將盤子由小到大逐個編號并放置在s上,即最小的盤子編號為1,放在最上面; ?(3)、按順時針方向把編號為1的盤子從當前的位置移動到下一位置; ?(4)、把另外兩個位置(即除去1號盤子所在的位置)中非空的那個上的一個圓盤移到空的位置上,如果另外兩個位置都非空,則移動編號較小的那一個; ?(5)、重復進行(3)和(4),直到移動的次數等于2^n-1。 ? -->? <script?type="text/javascript">? var?step=0; ? function?MoveOnePlate(n,?loca1,?loca2) ?{ ? ????document.write("第"?+?++step?+?"步:移動第<i>"?+?n?+?"</i>個盤子,從"?+?loca1?+?"到"?+?loca2?+?"<br?/>"); ? } ??function?MovePlates(n,?s,?m,?d) ?{ ?????//定義位置 ? ????var?loop=new?Array(3); ? ????loop[0]=new?Array(n); ?????loop[1]=new?Array(n); ?????loop[2]=new?Array(n); ?????//定義位置描述字符串數組(n為偶數的情況) ? ????var?loca=new?Array(s,?m,?d); ? ????if?(n%2!=0)?//n為奇數的情況 ?????{ ?????????loca[1]=d; ?????????loca[2]=m; ?????} ?????//初始化源位置上的盤子 ? ????for(var?i=0;?i<n;?i++) ? ????????loop[0][i]=n-i; ?????//記錄各個位置上盤子的數量 ? ????var?loopLen=new?Array(n,?0,?0); ? ????var?count=Math.pow(2,?n)-1;?//移動次數,即循環退出條件 ? ????var?firstPlate=0;?//1號盤子的位置 ? ????do ?????{ ?????????//將1號盤子順時針移動到后1個位置 ?????????MoveOnePlate(1,?loca[firstPlate],?loca[(firstPlate+1)%3]);?//顯示移動過程 ?????????loop[(firstPlate+1)%3][loopLen[(firstPlate+1)%3]]=1;?//移動 ?????????loopLen[firstPlate]--;?//修改1號盤子舊位置上盤子的數量 ? ????????firstPlate=(firstPlate+1)%3;?//修改1號盤子的位置 ? ????????loopLen[firstPlate]++;?//修改1號盤子新位置上盤子的數量 ?????????count--;?//記錄移動次數 ?????????//移動另外的兩個位置上的盤子 ?????????if(count!=0)?//避免最后一次移動后仍然移動而導致錯誤 ?????????{ ?????????????//確定另外兩個位置如何移動 ?????????????if?(loopLen[(firstPlate+1)%3]==0?||?loopLen[(firstPlate+2)%3]!=0?&& ? ????????????????loop[(firstPlate+2)%3][loopLen[(firstPlate+2)%3]-1]?<?loop[(firstPlate+1)%3][loopLen[(firstPlate+1)%3]-1]?) ? ????????????{?//1號盤子的后第1個位置為空,或者無空位置且1號盤子后第2個位置編號較小,此時將1號盤子后第2個位置的盤子移動到1號盤子后第1個位置上 ?????????????????MoveOnePlate(loop[(firstPlate+2)%3][loopLen[(firstPlate+2)%3]-1],?loca[(firstPlate+2)%3],?loca[(firstPlate+1)%3]);?//顯示移動過程 ?????????????????loop[(firstPlate+1)%3][loopLen[(firstPlate+1)%3]]=loop[(firstPlate+2)%3][loopLen[(firstPlate+2)%3]-1];?//移動 ?????????????????loopLen[(firstPlate+2)%3]--;?//修改該盤子舊位置上盤子的數量 ?????????????????loopLen[(firstPlate+1)%3]++;?//修改該盤子新位置上盤子的數量 ?????????????} ?????????????else ?????????????{?//1號盤子的后第2個位置為空,或者無空位置且1號盤子后第1個位置編號較小,此時將1號盤子后第1個位置的盤子移動到1號盤子后第2個位置上 ?????????????????MoveOnePlate(loop[(firstPlate+1)%3][loopLen[(firstPlate+1)%3]-1],?loca[(firstPlate+1)%3],?loca[(firstPlate+2)%3]);?//顯示移動過程 ?????????????????loop[(firstPlate+2)%3][loopLen[(firstPlate+2)%3]]=loop[(firstPlate+1)%3][loopLen[(firstPlate+1)%3]-1];?//移動 ?????????????????loopLen[(firstPlate+1)%3]--;?//修改該盤子舊位置上盤子的數量 ?????????????????loopLen[(firstPlate+2)%3]++;?//修改該盤子新位置上盤子的數量 ?????????????} ?????????????count--;?//記錄移動次數 ?????????} ?????}?while(count!=0) ?} ? </script>? </head>? ? <body>? <p>Hanoi?Tower?(Non-recursive?algorithm)?-?漢諾塔(非遞歸算法)<br?/>Mengliao?Software?Studio(Baiyu)?-?夢遼軟件工作室(白宇)<br?/>? Copyright?2011,?All?right?reserved.?-?版權所有(C)?2011<br?/>2011.03.31</p>? <script?type="text/javascript">? ????n=parseInt(prompt("請輸入盤子的數量:",?3),?10); ? ????if?(isNaN(n)?||?n<1?||?n>16) ? ????{ ?????????alert("請輸入介于1到16的自然數!"); ?????????location.reload(); ?????} ?????else ?????{ ? ????????document.write("共"?+?n?+?"個盤子,需移動"?+?(Math.pow(2,?n)-1)?+?"步:<br?/><br?/>"); ? ????????MovePlates(n,?"<i>源點</i>",?"<i>臨時</i>",?"<i>目標</i>"); ? ????} ? </script>? </body>? </html>? 非遞歸算法略微復雜些,代碼里面有詳細的注釋和說明。
這里還有一個使用JavaScript數組對象的push()和pop()方法的非遞歸版本,可以簡化程序,道理是一樣的。
非遞歸算法版本2:?
<html?xmlns="http://www.w3.org/1999/xhtml">? <head>? ????<meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>? ????<title>Hanoi?Tower?(Non-recursive?algorithm,?Version?2)?-?漢諾塔(非遞歸算法,版本2)</title>? ????<style?type="text/css">? ????????i ?????????{ ?????????????color:?#ff0080; ?????????} ?????????p ?????????{ ?????????????text-align:?center; ?????????} ? ????</style>? ????<!-- ?漢諾塔非遞歸算法: ?(1)、若問題規模n為偶數,按順時針方向依次擺放s,?m,?d為環,若n為奇數,則為s,?d,?m; ?(2)、將盤子由小到大逐個編號并放置在s上,即最小的盤子編號為1,放在最上面; ?(3)、按順時針方向把編號為1的盤子從當前的位置移動到下一位置; ?(4)、把另外兩個位置(即除去1號盤子所在的位置)中非空的那個上的一個圓盤移到空的位置上,如果另外兩個位置都非空,則移動編號較小的那一個; ?(5)、重復進行(3)和(4),直到移動的次數等于2^n-1。 ? -->? ????<script?type="text/javascript">? ????????var?step?=?0; ? ????????function?MoveOnePlate(n,?loca1,?loca2)?{ ? ????????????document.write("第"?+?++step?+?"步:移動第<i>"?+?n?+?"</i>個盤子,從"?+?loca1?+?"到"?+?loca2?+?"<br?/>"); ? ????????} ??????????function?MovePlates(n,?s,?m,?d)?{ ?????????????//定義位置 ? ????????????var?loop?=?new?Array([],?[],?[]); ? ????????????//定義位置描述字符串數組(n為偶數的情況) ? ????????????var?loca?=?new?Array(s,?m,?d); ? ????????????if?(n?%?2?!=?0)?//n為奇數的情況 ?????????????{ ?????????????????loca[1]?=?d; ?????????????????loca[2]?=?m; ?????????????} ?????????????//初始化源位置上的盤子 ? ????????????for?(var?i?=?0;?i?<?n;?i++) ? ????????????????loop[0].push(n?-?i); ? ????????????var?count?=?Math.pow(2,?n)?-?1;?//移動次數,即循環退出條件 ? ????????????var?firstPlate?=?0;?//1號盤子的位置 ? ????????????do?{ ?????????????????//將1號盤子順時針移動到后1個位置 ?????????????????MoveOnePlate(1,?loca[firstPlate],?loca[(firstPlate?+?1)?%?3]);?//顯示移動過程 ?????????????????loop[(firstPlate?+?1)?%?3].push(loop[firstPlate].pop());?//從舊位置移動到新位置 ? ????????????????firstPlate?=?(firstPlate?+?1)?%?3;?//修改1號盤子的位置 ? ????????????????count--;?//記錄移動次數 ?????????????????//移動另外的兩個位置上的盤子 ?????????????????if?(count?!=?0)?//避免最后一次移動后仍然移動而導致錯誤 ?????????????????{ ?????????????????????//確定另外兩個位置如何移動 ? ????????????????????if?(loop[(firstPlate?+?1)?%?3].length?==?0?||?loop[(firstPlate?+?2)?%?3].length?!=?0?&&?loop[(firstPlate?+?2)?%?3][loop[(firstPlate?+?2)?%?3].length?-?1]?<?loop[(firstPlate?+?1)?%?3][loop[(firstPlate?+?1)?%?3].length?-?1])?{ ? ????????????????????????//1號盤子的后第1個位置為空,或者無空位置且1號盤子后第2個位置編號較小,此時將1號盤子后第2個位置的盤子移動到1號盤子后第1個位置上 ?????????????????????????MoveOnePlate(loop[(firstPlate?+?2)?%?3][loop[(firstPlate?+?2)?%?3].length?-?1],?loca[(firstPlate?+?2)?%?3],?loca[(firstPlate?+?1)?%?3]);?//顯示移動過程 ?????????????????????????loop[(firstPlate?+?1)?%?3].push(loop[(firstPlate?+?2)?%?3].pop());?//從舊位置移動到新位置 ?????????????????????} ?????????????????????else?{ ?????????????????????????//1號盤子的后第2個位置為空,或者無空位置且1號盤子后第1個位置編號較小,此時將1號盤子后第1個位置的盤子移動到1號盤子后第2個位置上 ?????????????????????????MoveOnePlate(loop[(firstPlate?+?1)?%?3][loop[(firstPlate?+?1)?%?3].length?-?1],?loca[(firstPlate?+?1)?%?3],?loca[(firstPlate?+?2)?%?3]);?//顯示移動過程 ?????????????????????????loop[(firstPlate?+?2)?%?3].push(loop[(firstPlate?+?1)?%?3].pop());?//從舊位置移動到新位置 ?????????????????????} ?????????????????????count--;?//記錄移動次數 ?????????????????} ?????????????}?while?(count?!=?0) ?????????} ? ????</script>? </head>? <body>? ????<p>? ????????Hanoi?Tower?(Non-recursive?algorithm,?Version?2)?-?漢諾塔(非遞歸算法,版本2)<br?/>? ????????Mengliao?Software?Studio(Baiyu)?-?夢遼軟件工作室(白宇)<br?/>? ????????Copyright?2011,?All?right?reserved.?-?版權所有(C)?2011<br?/>? ????????2011.04.04</p>? ????<script?type="text/javascript">? ????????n?=?parseInt(prompt("請輸入盤子的數量:",?3),?10); ? ????????if?(isNaN(n)?||?n?<?1?||?n?>?16)?{ ? ????????????alert("請輸入介于1到16的自然數!"); ?????????????location.reload(); ?????????} ?????????else?{ ? ????????????document.write("共"?+?n?+?"個盤子,需移動"?+?(Math.pow(2,?n)?-?1)?+?"步:<br?/><br?/>"); ? ????????????MovePlates(n,?"<i>源點</i>",?"<i>臨時</i>",?"<i>目標</i>"); ? ????????} ? ????</script>? </body>? </html>? 這里是三個算法網頁源文件的連接:
http://mengliao.blog.51cto.com/attachment/201104/876134_1301907387.rar
本文轉自 BlackAlpha 51CTO博客,原文鏈接:http://blog.51cto.com/mengliao/534053,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的汉诺塔非递归算法的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。