這兩天講《Web程序設計》,用JavaScript寫了個漢諾塔的非遞歸算法,以爲有點意思,放在這裏吧!javascript
傳統的遞歸算法: css
- <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>
這個遞歸算法就不詳細說了,核心代碼只有五、6行。
下面是非遞歸算法: html
- <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>
非遞歸算法略微複雜些,代碼裏面有詳細的註釋和說明。java
這裏還有一個使用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/p_w_upload/201104/876134_1301907387.rar數組