汉诺塔问题简述:将塔A上的n个大小不一的盘子借由塔B全部移动到塔C上,且在过程中不能将大盘子放在小盘子上。
目录
汉诺塔问题虽然是经典的用递归方法求解的一个问题,但是对于一个看见递归就脑阔疼的人来说,还是想走走其他的路,因此我选择使用非递归来解决这个问题,具体如下:
算法:
不要问为什么可以这样做,问就是有一个美国学者研究表明
具体效果:
PS:千万别把n设置的过大,输出不完的,因为要2^n-1次移动才能完成任务,当n=10的时候就已经要进行1023次移动了。
详细代码如下:
SeqStack.cpp文件
主要任务:定义一个顺序栈,并且稍微修改其getTop()函数(与数据结构教材中定义的get函数一点点不同),设置当top指针指向-1时,调用getTop()函数则会返回999,避免塔已经空了还在移动空气到另外一个塔上。在后面的函数时会用到。
const int StackSize = 100; //设置储存数组的大小为100
template <class DataType>
class SeqStack
{
public:
SeqStack(); //初始化一个空栈,存储数组中什么都没有,令top=-1
~SeqStack(); //不需要事实上,静态存储分配
void Push(DataType x); //入栈函数,令top++,收入x
DataType Pop(); //出栈函数,送走栈顶元素,令top--;
DataType GetTop(); //取栈顶元素,仅仅是取
int Empty(); //判空函数
private:
DataType data[StackSize]; //定义存储数组
int top; //令附设变量top为-1
};
template<class DataType>
SeqStack<DataType>::SeqStack(){
top = -1; //存储结构已经定义,在这里仅仅只需要令top为-1就行了
}
template<class DataType>
SeqStack<DataType>::~SeqStack(){
}
template<class DataType>
void SeqStack<DataType>::Push(DataType x)
{
if (top == StackSize - 1)throw"入栈失败,栈已满";
top++;
data[top] = x;
}
template<class DataType>
DataType SeqStack<DataType>::Pop()
{
DataType x;
if (top == -1)throw "出栈失败,栈已空";
x = data[top--];
return x;
}
template<class DataType>
DataType SeqStack<DataType>::GetTop(){
if (top != -1)return data[top];
else return 999; //设置底座为999,这样就不会发生从空底座取盘子的情况。
}
template<class DataType>
int
SeqStack<DataType>::Empty(){
if (top == -1)return 1;
else return 0;
}
Hanoi_main.cpp文件
主要任务:创建塔A,塔B,塔C,他们都是栈。然后将n个盘子放到A塔上,调用函数将n个盘子借由B塔移动到C塔上。
其中n为塔A的初始盘子数
i为移动的次数,每进行一次移动都会加一,当达到2^n-1次,即刻停止
/*
显然,汉诺塔问题符合栈的特点,后进先出;因此在这里我们要使用栈来解决
*/
#include <iostream>
#include <cmath>
#include "SeqStack.cpp"
using namespace std;
void putplate(int n, SeqStack<int> &A);
//将n个盘子从大到小,低到高堆到塔A上的函数原型
int operate1inA(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n);
//n为偶数且当最小的一号盘子在A塔时的处理方法
int operate1inB(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n);
//n为偶数且当最小的一号盘子在B塔时的处理方法
int operate1inC(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n);
//n为偶数且当最小的一号盘子在C塔时的处理方法
int operate1inOddA(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n);
//n为奇数且当最小的一号盘子在A塔时的处理方法
int operate1inOddB(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n);
//n为奇数且当最小的一号盘子在B塔时的处理方法
int operate1inOddC(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n);
//n为奇数且当最小的一号盘子在C塔时的处理方法
int main()
{
int n;
cout << "请输入宝塔A的盘子数" << endl;
cin >> n;
SeqStack<int>A; //定义塔A
SeqStack<int>B; //定义塔B
SeqStack<int>C; //定义塔C
putplate(n,A); //将n个盘子从依次放到塔A上,从上到下序号逐渐变大
try{
if (n % 2 == 0){ //n为偶数
for (int i = 0;;) //当盘子的个数为n时,移动的次数应等于2^n - 1
{
if (A.GetTop() == 1){ //如果1号盘在A,移动到B
if (operate1inA(A, B, C, i, n)){ //如果达到上限次数,终止循环
break;
}
}
else if (B.GetTop() == 1){ //在B则移动到C
if (operate1inB(A, B, C, i, n)){
break;
}
}
else if (C.GetTop() == 1){ //在C则移动到A
if (operate1inC(A, B, C, i, n)){
break;
}
}
}
}
else {
for (int i = 0;;)
{
if (A.GetTop() == 1){ //如果1号盘在A,移动到C
if (operate1inOddA(A, B, C, i, n)){ //如果达到上限次数,终止循环
break;
}
}
else if (B.GetTop() == 1){ //在B则移动到A
if (operate1inOddB(A, B, C, i, n)){
break;
}
}
else if (C.GetTop() == 1){ //在C则移动到B
if (operate1inOddC(A, B, C, i, n)){
break;
}
}
}
}
}
catch (char *r){
cout << r << endl;
}
system("pause");
return 0;
}
void putplate(int n, SeqStack<int> &A){ //将n个盘子从依次放到塔A上,从上到下序号逐渐变大
for (int i = n; i >= 1; i--){
A.Push(i); //i入栈
}
return;
}
int operate1inA(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n){
B.Push(1); //将一号盘放入B塔
A.Pop();
i++; //盘子的移动次数加一
cout << "将1号盘子从A塔移动到B塔" << endl;
if (i >= (pow(2, n) - 1)){ //如果移动次数达到了2^n-1,即刻停止
return 1; //1用于给if判断终止循环
}
if (C.GetTop() < A.GetTop()){ //将另外两个塔上的可以进行移动的盘子进行移动,
//事实上1号盘所在的塔不可能被放盘子,所以只要判断其他两个塔即可
cout << "将" << C.GetTop() << "号盘子从C塔移动到A塔" << endl;
A.Push(C.GetTop()); //如果C塔的最高盘子可以移动,则拿出C塔的最高盘子放入A
C.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
else if (A.GetTop() < C.GetTop()){
cout << "将" << A.GetTop() << "号盘子从A塔移动到C塔" << endl;
C.Push(A.GetTop()); //如果A塔的最高盘子可以移动,则拿出A塔的最高盘子放入C
A.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
return 0; //没有达到上限次数,不终止循环
}
int operate1inB(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n){
B.Pop();
C.Push(1);
i++;
cout << "将1号盘子从B塔移动到C塔" << endl;
if (i >= (pow(2, n) - 1)){
return 1;
}
if (B.GetTop() < A.GetTop()){
cout << "将" << B.GetTop() << "号盘子从B塔移动到A塔" << endl;
A.Push(B.GetTop());
B.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
else if (A.GetTop() < B.GetTop()){
cout << "将" << A.GetTop() << "号盘子从A塔移动到B塔" << endl;
B.Push(A.GetTop());
A.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
return 0;
}
int operate1inC(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n){
C.Pop();
A.Push(1);
i++;
cout << "将1号盘子从C塔移动到A塔" << endl;
if (i >= (pow(2, n) - 1)){
return 1;
}
if (B.GetTop() < C.GetTop()){
cout << "将" << B.GetTop() << "号盘子从B塔移动到C塔" << endl;
C.Push(B.GetTop());
B.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
else if (C.GetTop() < B.GetTop()){
cout << "将" << C.GetTop() << "号盘子从C塔移动到B塔" << endl;
B.Push(C.GetTop());
C.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
return 0;
}
int operate1inOddA(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n){
C.Push(1); //将一号盘放入C塔
A.Pop();
i++; //盘子的移动次数加一
cout << "将1号盘子从A塔移动到C塔" << endl;
if (i >= (pow(2, n) - 1)){ //如果移动次数达到了2^n-1,即刻停止
return 1; //1用于给if判断终止循环
}
if (B.GetTop() < A.GetTop()){
cout << "将" << B.GetTop() << "号盘子从B塔移动到A塔" << endl;
A.Push(B.GetTop()); //如果C塔的最高盘子可以移动,则拿出C塔的最高盘子放入
B.Pop();
i++;
if (i >= (pow(2, n) - 1)){ //如果移动次数达到了2^n-1,即刻停止
return 1;
}
}
else if (A.GetTop() < B.GetTop()){
cout << "将" << A.GetTop() << "号盘子从A塔移动到B塔" << endl;
B.Push(A.GetTop());
A.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
return 0;
}
int operate1inOddC(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n){
C.Pop();
B.Push(1);
i++;
cout << "将1号盘子从C塔移动到B塔" << endl;
if (i >= (pow(2, n) - 1)){
return 1;
}
if (C.GetTop() < A.GetTop()){
cout << "将" << C.GetTop() << "号盘子从C塔移动到A塔" << endl;
A.Push(C.GetTop());
C.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
else if (A.GetTop() < C.GetTop()){
cout << "将" << A.GetTop() << "号盘子从A塔移动到C塔" << endl;
C.Push(A.GetTop());
A.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
return 0;
}
int operate1inOddB(SeqStack<int>&A, SeqStack<int>&B, SeqStack<int>&C, int &i, int n){
B.Pop();
A.Push(1);
i++;
cout << "将1号盘子从B塔移动到A塔" << endl;
if (i >= (pow(2, n) - 1)){
return 1;
}
if (B.GetTop() < C.GetTop()){
cout << "将" << B.GetTop() << "号盘子从B塔移动到C塔" << endl;
C.Push(B.GetTop());
B.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
else if (C.GetTop() < B.GetTop()){
cout << "将" << C.GetTop() << "号盘子从C塔移动到B塔" << endl;
B.Push(C.GetTop());
C.Pop();
i++;
if (i >= (pow(2, n) - 1)){
return 1;
}
}
return 0;
}