汉诺塔的递归算法很容易理解,也非常容易实现。下面,本文讨论了汉诺塔问题的非递归算法,核心内容就是栈的使用技巧。
首先,对于每个柱子来说,就是一个栈,这个栈有个特点就是,大数放在下面,小数放在上面。在首次建立栈时,我们可以先存储好这些数据,假设最小的盘子序号为1,后面的由此类推。在建立栈时,根据当前盘子总数是否为偶数,需要调整B、C两个柱子的位置。当n为偶数时,按照A、B、C的顺序排放三个柱子,当n为奇数时,按照A、C、B的顺序排列这些柱子。这两个顺序就是汉诺塔中最小的那个盘子的挪动顺序。
其次,建立好栈后,接下来就是算法的核心部分了。初始情况下,需要首先挪动最小的那个盘子,把编号为1的那个盘子挪动到它的下一个位置上(有可能是B,也有可能是C),这时需要判断一下,程序是否已经完成了,若还没有完成,则继续下面的步骤。下一步,判断当前剩下的两个柱子的栈顶元素,如果有个栈顶元素为0,说明该柱子上没有盘子,把非零的栈顶元素放入空栈中;如果两个栈顶元素都是非零的,则将较小的元素移动到较大的元素上面。
再次,此时一轮循环已经结束,再次移动编号为1的盘子,将它移动到它的下一个位置上面。
最后,重复上面的步骤,当循环结束时,我们的算法就运行完了。
// NonRecursionHanoi.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<iostream>
using namespace std;
const int MAX = 64;
struct st
{
char name;
int array[MAX];
int topIndex;
int TopData( void )
{
if( topIndex == 0 )
{
return 0;
}
else
{
return array[topIndex-1];
}
}
int Pop( void )
{
int retVal = array[topIndex-1];
--topIndex;
array[topIndex] = 0;
return retVal;
}
void Push( int data )
{
array[topIndex] = data;
++topIndex;
}
};
long int expo( int x, int y )
{
long retVal = 1;
for( int i = 0; i < y; i++ )
{
retVal = retVal * x;
}
return retVal;
}
void CreateHanoi( st pillar[], int n )
{
pillar[0].name = 'A';
for(int i = 0; i < n; i++ )
{
pillar[0].array[i] = n - i;
}
pillar[0].topIndex = n;
for( int i = 0; i < n; i++ )
{
pillar[2].array[i] = pillar[1].array[i] = 0;
}
pillar[2].topIndex = pillar[1].topIndex = 0;
if( n%2 == 0 )
{
pillar[1].name = 'B';
pillar[2].name = 'C';
}
else
{
pillar[1].name = 'C';
pillar[2].name = 'B';
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int n;
cout<<"Please input the disk number:";
cin>>n;
while ( ( n > 64 ) || ( n < 1 ) )
{
cout<<"\r\nInput a New number, must between 1 and 64"<<endl;
cin>>n;
}
st pillar[3];
CreateHanoi( pillar, n );
int max = expo( 2, n ) - 1; // Move n Disks need max steps.
int k = 0; // Record the Current move steps.
int j = 0; // Record 1st disk's position.
while( k < max )
{
int temp = pillar[j%3].Pop();
pillar[(j+1)%3].Push(temp);
cout<<++k<<" "<<pillar[j%3].name<<"->"<<pillar[(j+1)%3].name<<endl;
++j;
int temp1 = pillar[(j-1)%3].TopData();
int temp2 = pillar[(j+1)%3].TopData();
if( k < max )
{
if( ( temp2 == 0 ) || ( ( temp1 > 0 ) && ( temp2 > temp1 ) ) )
{
temp = pillar[(j-1)%3].Pop();
pillar[(j+1)%3].Push(temp);
cout<<++k<<" "<<pillar[(j-1)%3].name<<"->"<<pillar[(j+1)%3].name<<endl;
}
else
{
temp = pillar[(j+1)%3].Pop();
pillar[(j-1)%3].Push(temp);
cout<<++k<<" "<<pillar[(j+1)%3].name<<"->"<<pillar[(j-1)%3].name<<endl;
}
}
}
getchar();
getchar();
return 0;
}