汉诺塔问题本身用递归实现是很简便的,本题其实还是为了加深对堆栈的理解运用,所以用标准的堆栈来模拟递归的过程。
题目
借助堆栈以非递归(循环)方式求解汉诺塔的问题(n, a, b, c),即将N个盘子从起始柱(标记为“a”)通过借助柱(标记为“b”)移动到目标柱(标记为“c”),并保证每个移动符合汉诺塔问题的要求。
输入格式:
输入为一个正整数N,即起始柱上的盘数。
输出格式:
每个操作(移动)占一行,按柱1 -> 柱2的格式输出。
输入样例:
3
输出样例:
a -> c
a -> b
c -> b
a -> c
b -> a
b -> c
a -> c
思路:
不用递归用循环,就需要用到堆栈先进后出的特性来模拟递归,将问题放入堆栈,然后不断将栈顶问题分解,将分解的n-1个问题放入堆栈,这样循环直到堆栈为空。以3个为例。
根据汉诺塔问题的思路,构造堆栈,模拟这个过程,还是以3个为例,可以对照代码看(画的有点丑)
代码
定义堆栈及函数声明
#include<stdio.h>
#include<stdlib.h>
#define Maxsize 100
typedef enum { False, True }Bool;
typedef struct {
int N;//盘数
char A;
char B;
char C;
}ElementType;
typedef int Position;
typedef struct SNode* PtrToSNode;
struct SNode {
ElementType* Data;
Position Top;
int MaxSize;
};
typedef PtrToSNode Stack;
Stack CreateStack(int MaxSize);
bool IsEmpty(Stack S);
void Push(Stack S, ElementType X);
ElementType Pop(Stack S);
Hanoi函数及主函数
void Hanoi(int n) {
Stack S;
ElementType P, toPush;
S = CreateStack(Maxsize);
P.N = n; P.A = 'a'; P.B = 'b'; P.C = 'c';
Push(S, P);//将初始问题放入堆栈(n,a,b,c)
while (1) {
P = Pop(S);
if (P.N == 1) {
if (IsEmpty(S)) {
printf("%c -> %c", P.A, P.C);
break;
}
else {
printf("%c -> %c\n", P.A, P.C);
}
}
else {
toPush.N = P.N - 1;
toPush.A = P.B;
toPush.B = P.A;
toPush.C = P.C;
Push(S, toPush);//将第二个待解子问题入栈(n-1,b,a,c)
toPush.N = 1;
toPush.A = P.A;
toPush.B = P.B;
toPush.C = P.C;
Push(S, toPush);//将可直接求解的子问题(1,a,b,c)入栈
toPush.N = P.N - 1;
toPush.A = P.A;
toPush.B = P.C;
toPush.C = P.B;
Push(S, toPush);//将第一个待解子问题(n-1,a,c,b)入栈
}
}
}
int main() {
int N;
scanf("%d",&N);
Hanoi(N);
return 0;
}
其他函数
Stack CreateStack(int MaxSize) {
Stack S = (Stack)malloc(sizeof(struct SNode));
S->Data = (ElementType*)malloc(Maxsize * sizeof(ElementType));
S->Top = -1;
S->MaxSize = MaxSize;
return S;
}
bool IsEmpty(Stack S) {
return (S->Top == -1);
}
void Push(Stack S, ElementType X) {
S->Data[++(S->Top)] = X;
}
ElementType Pop(Stack S) {
return S->Data[(S->Top)--];
}