本文目錄一覽:
用java編寫hanoi塔的非遞歸演算法。
這是個好問題,很少看到有人寫漢諾塔的非遞歸…其實只要先寫出遞歸,然後把遞歸的每一步要做的事情記錄在一個棧裡面就可以了
public class Test {
private static void emitStep(int source, int dest) {
System.out.println(source + ” – ” + dest);
}
static class Step {
Step(int n, int s, int d, int t) {
this.n = n;
source = s;
dest = d;
temp = t;
}
int n, source, dest, temp;
}
private static void hanoi(int n, int source, int dest, int temp) {
java.util.StackStep steps = new java.util.StackStep();
steps.add(new Step(n, source, dest, temp));
while (steps.empty() == false) {
Step step = steps.pop();
if (step.n == 1) {
emitStep(step.source, step.dest);
continue;
}
steps.push(new Step(step.n – 1, step.temp, step.dest, step.source));
steps.push(new Step(1, step.source, step.dest, 0));
steps.push(new Step(step.n – 1, step.source, step.temp, step.dest));
}
}
public static void main(String[] args) {
hanoi(3, 1, 3, 2);
}
}
漢諾塔非遞歸的寫法
以前寫過
#include iostream
using namespace std;
//圓盤的個數最多為64
const int MAX = 64;
//用來表示每根柱子的信息
struct st{
int s[MAX]; //柱子上的圓盤存儲情況
int top; //棧頂,用來最上面的圓盤
char name; //柱子的名字,可以是A,B,C中的一個
int Top()//取棧頂元素
{
return s[top];
}
int Pop()//出棧
{
return s[top–];
}
void Push(int x)//入棧
{
s[++top] = x;
}
} ;
long Pow(int x, int y); //計算x^y
void Creat(st ta[], int n); //給結構數組設置初值
void Hannuota(st ta[], long max); //移動漢諾塔的主要函數
int main(void)
{
int n;
cin n; //輸入圓盤的個數
st ta[3]; //三根柱子的信息用結構數組存儲
Creat(ta, n); //給結構數組設置初值
long max = Pow(2, n) – 1;//動的次數應等於2^n – 1
Hannuota(ta, max);//移動漢諾塔的主要函數
system(“pause”);
return 0;
}
void Creat(st ta[], int n)
{
ta[0].name = ‘A’;
ta[0].top = n-1;
//把所有的圓盤按從大到小的順序放在柱子A上
for (int i=0; in; i++)
ta[0].s[i] = n – i;
//柱子B,C上開始沒有沒有圓盤
ta[1].top = ta[2].top = 0;
for (int i=0; in; i++)
ta[1].s[i] = ta[2].s[i] = 0;
//若n為偶數,按順時針方向依次擺放 A B C
if (n%2 == 0)
{
ta[1].name = ‘B’;
ta[2].name = ‘C’;
}
else //若n為奇數,按順時針方向依次擺放 A C B
{
ta[1].name = ‘C’;
ta[2].name = ‘B’;
}
}
long Pow(int x, int y)
{
long sum = 1;
for (int i=0; iy; i++)
sum *= x;
return sum;
}
void Hannuota(st ta[], long max)
{
int k = 0; //累計移動的次數
int i = 0;
int ch;
while (k max)
{
//按順時針方向把圓盤1從現在的柱子移動到下一根柱子
ch = ta[i%3].Pop();
ta[(i+1)%3].Push(ch);
cout ++k “: ”
“Move disk ” ch ” from ” ta[i%3].name
” to ” ta[(i+1)%3].name endl;
i++;
//把另外兩根柱子上可以移動的圓盤移動到新的柱子上
if (k max)
{ //把非空柱子上的圓盤移動到空柱子上,當兩根柱子都為空時,移動較小的圓盤
if (ta[(i+1)%3].Top() == 0 ||
ta[(i-1)%3].Top() 0
ta[(i+1)%3].Top() ta[(i-1)%3].Top())
{
ch = ta[(i-1)%3].Pop();
ta[(i+1)%3].Push(ch);
cout ++k “: ” “Move disk “
ch ” from ” ta[(i-1)%3].name
” to ” ta[(i+1)%3].name endl;
}
else
{
ch = ta[(i+1)%3].Pop();
ta[(i-1)%3].Push(ch);
cout ++k “: ” “Move disk “
ch ” from ” ta[(i+1)%3].name
” to ” ta[(i-1)%3].name endl;
}
}
}
}
誰會漢諾塔非遞歸的編程(java),並真正了解含義
public class Hannuota {
private int n;//儲存檔子個數
public Hannuota(int n){
this.n = n;
}
public void function(){
//初始化三個柱子,A是開始堆滿盤子的柱子,C是目標柱子
Pillar a = new Pillar(n,n,”A”);
Pillar b = new Pillar(n,”B”);
Pillar c = new Pillar(n,”C”);
//把三個柱子按順序排好,詳見後面的演算法那裡的解釋
Pillar[] pillars = new Pillar[3];
pillars[0] = a;
if(n%2==0){
pillars[1] = b;
pillars[2] = c;
}else{
pillars[1] = c;
pillars[2] = b;
}
//開始移動,k用來計數,移動次數為2^n-1,至於為什麼,我不太清楚,
//反正有人證明過。i是用來保存最小那個盤子正在哪跟柱子上的。
int i=0;
for(int k=0;k(int)Math.pow(2, n)-1;){
int min;
//將最小的盤子順時針移動一個柱子
min = pillars[i%3].Pop();
pillars[(i+1)%3].Push(min);
System.out.println(pillars[i%3]+”-“+pillars[(i+1)%3]);
k++;
i++;
//這個IF好像可以不要,當時寫的,後面忘了刪除。
if(k(int)Math.pow(2, n)-1){
//如果,剩下兩根柱子中,某一根為空,則一定是非空那根中最上面個盤子
//移動到空的那個柱子上。若兩根都不為空,則把編號小的一個盤子
//移動到另外跟柱子上
if(!pillars[(i-1)%3].isEmpty()(pillars[(i+1)%3].isEmpty()||pillars[(i+1)%3].Top()pillars[(i-1)%3].Top())){
min=pillars[(i-1)%3].Pop();
pillars[(i+1)%3].Push(min);
System.out.println(pillars[(i-1)%3]+”-“+pillars[(i+1)%3]);
}else{
min=pillars[(i+1)%3].Pop();
pillars[(i-1)%3].Push(min);
System.out.println(pillars[(i+1)%3]+”-“+pillars[(i-1)%3]);
}
k++;
}
}
}
//主函數,用來測試的。3表示3個盤子。
public static void main(String args[]){
new Hannuota(3).function();
}
}
class Pillar{//構造一個新類,表示柱子,實際是當一個棧在用
private int[] s;
private int top;
private String name;
public String toString(){
return name;
}
//這個構造函數用來構造BC兩個柱子,下面那個用來構造柱子A。其實也可以寫成一個構造函數。
public Pillar(int max,String name){
s = new int[max];
top = -1;
this.name = name;
for(int i=0;i s[i] = max+1;
}
}
public Pillar(int n,int max,String name){
s = new int[max];
top = n-1;
this.name = name;
for(int i=0;i s[i] = max – i;
}
}
//這後面這些就是棧的基本方法了,不用介紹了吧
public boolean isEmpty(){
return top==-1?true:false;
}
public int Top (){
return s[top];
}
public int Pop(){
return s[top–];
}
public void Push(int x){
s[++top] = x;
}
}
演算法是這個
首先容易證明,當盤子的個數為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)操作,最後就能按規定完成漢諾塔的移動。
這玩意要非遞歸真麻煩。需不需要加點注釋?
原創文章,作者:CYX7P,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/127705.html