漢諾塔非遞迴演算法
這兩天講《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,如需轉載請自行聯絡原作者
相關文章
- 漢諾塔非遞迴棧程式碼遞迴
- 漢諾塔和遞迴遞迴
- 漢諾塔的圖解遞迴演算法圖解遞迴演算法
- 經典遞迴解決漢諾塔!遞迴
- 遞迴實現漢諾塔問題遞迴
- c++遞迴與迭代實現漢諾塔C++遞迴
- 從漢諾塔遊戲理解python遞迴函式遊戲Python遞迴函式
- python3:遞迴解漢諾塔問題Python遞迴
- C#中漢諾塔問題的遞迴解法C#遞迴
- 化繁為簡 經典的漢諾塔遞迴問題 in Java遞迴Java
- 漢諾塔遊戲《演算法很美》遊戲演算法
- 漢諾塔演算法演示1.0演算法
- 快速排序(遞迴及非遞迴演算法原始碼)排序遞迴演算法原始碼
- PHP實現漢諾塔演算法PHP演算法
- 遞迴演算法轉換為非遞迴演算法的技巧遞迴演算法
- 【YbtOJ高效進階 遞推-2】奇怪漢諾塔
- 揹包問題的遞迴與非遞迴演算法遞迴演算法
- SQL 漢諾塔SQL
- 快速排序【遞迴】【非遞迴】排序遞迴
- 第二章 :查詢與排序-------遞迴經典問題——漢諾塔問題排序遞迴
- 漢諾塔詳解
- 漢諾塔-PythonPython
- ACM 漢諾塔(三)ACM
- 【演算法拾遺】二分查詢遞迴非遞迴實現演算法遞迴
- 二叉樹建立及遍歷演算法(遞迴及非遞迴)二叉樹演算法遞迴
- 漢諾塔的實現
- 漢諾塔通項公式公式
- 二十一、氣泡排序演算法——JAVA實現(遞迴與非遞迴)排序演算法Java遞迴
- 二叉樹——後序遍歷的遞迴與非遞迴演算法二叉樹遞迴演算法
- 遍歷二叉樹-------遞迴&非遞迴二叉樹遞迴
- 氣泡排序、快速排序(遞迴&非遞迴)、堆排序演算法比較淺析排序遞迴演算法
- 【分治演算法】歸併排序,快速排序和漢諾塔演算法排序
- JAVA漢諾塔遞迴 之SpringCloud企業分散式微服務雲架構快速開發平臺Java遞迴SpringGCCloud分散式微服務架構
- 百練OJ:4147:漢諾塔問題(Hanoi)——python實現漢諾塔Python
- 奇怪的漢諾塔 - 題解
- 小知識系列(3):Hanoi塔(漢諾塔,河內塔)
- 五大演算法程式碼模板(DFS 遞迴非遞迴都算上,是六個)演算法遞迴
- JavaScript斐波納契數列非遞迴演算法JavaScript遞迴演算法