如有不对,不吝赐教
进入正题:
借助堆栈以非递归(循环)方式求解汉诺塔的问题(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
这个题目要求我们用反常规的思维去思考汉诺塔问题,其实是对自己思维的一个锻炼,
这个题目的关键是用堆去实现函数递归中的栈调用
下面就以3个为例来分析
我们把从下到上的编号为3,2,1
以及栈的构造:
typedef struct Stack{
int num; //柱子的编号
char source; //源
char destination; //目标
char mid; //中间的柱子
struct Stack *down;
}stack;
下面我们将塔看为最底下的一个盘(即3)并上面的所有盘作为一个盘(即2和1),那么问题变为了两个盘,这个移动就很简单了。
我们先把1,2盘移动到b,再把3移动到c,最后再把1,2盘移动到c
这在栈里面的操作就是 Push 3:a->c
为了将3移动出来,我们要把1,2放到b,于是问题就变成了怎么把1,2放到b,按照上面的分发,栈中的操作就是Push 2:a->b,然后就变成了怎么把1放到c,执行Push:a->c
代码就是:
top=(stack *)malloc(sizeof(stack));
top->down=NULL;
top->source='a';
top->mid='b';
top->destination='c';
top->num=N; //初始化第一个栈节点
i=N-1;
while(i){
top=Push(i,top->source,top->destination,top->mid,top);
i--;
}
现在栈中的状态就是这样的:
然后我们要开始执行操作,Pop就相当于执行栈顶的操作
Pop 1:a->c后,stack和汉诺塔变成:
然后就是执行Pop 2:a->b,根据前面的分析,在执行这个操作后,1,2盘应该到了b上面但实际上是这样的:
所以我们还得在Pop完后在向其中把1盘放回b,即:Push 1:c->b
然后stack变成了这样:
这一步的操作就是这样的:
result=Pop(&top);
printf("%c -> %c\n",result->source,result->destination);
i=result->num-1;
if(!i)
continue;
stack *newOne;
newOne=(stack *)malloc(sizeof(stack));
newOne->num=i--;
newOne->source=result->mid;
newOne->mid=result->source;
newOne->destination=result->destination;
newOne->down=top;
top=newOne;
free(result);
while(i){
top=Push(i,top->source,top->destination,top->mid,top);
i--;
}
}
然后在进行Pop 1:c->b操作,就成了这样:
然后就是一样的操作,就可以把3放到c,1,2放到了b,于是问题就变成了把1,2从b放到c
问题就得以简化了
下面给出代码:
#include<stdio.h>
#include<malloc.h>
typedef struct Stack{
int num; //柱子的编号
char source; //源
char destination; //目标
char mid; //中间的柱子
struct Stack *down;
}stack;
stack *Push(int num,char source,char mid,char destination,stack *top);
stack *Pop(stack **top);
int main(void)
{
int N,i;
stack *top;
stack *result;
scanf("%d",&N);
top=(stack *)malloc(sizeof(stack));
top->down=NULL;
top->source='a';
top->mid='b';
top->destination='c';
top->num=N; //初始化第一个栈节点
i=N-1;
while(i){
top=Push(i,top->source,top->destination,top->mid,top);
i--;
}
while(top){
result=Pop(&top);
printf("%c -> %c\n",result->source,result->destination);
i=result->num-1;
if(!i)
continue;
stack *newOne;
newOne=(stack *)malloc(sizeof(stack));
newOne->num=i--;
newOne->source=result->mid;
newOne->mid=result->source;
newOne->destination=result->destination;
newOne->down=top;
top=newOne;
free(result);
while(i){
top=Push(i,top->source,top->destination,top->mid,top);
i--;
}
}
return 0;
}
stack *Push(int num,char source,char mid,char destination,stack *top)
{
stack *newOne;
newOne=(stack *)malloc(sizeof(stack));
newOne->num=num;
newOne->down=top;
newOne->source=source; //重置三个柱子
newOne->mid=mid;
newOne->destination=destination;
top=newOne;
return top;
}
stack *Pop(stack **top)
{
stack *mid;
mid=*top;
*top=(*top)->down;
return mid;
}