PTA 数据结构与算法 7-17 汉诺塔的非递归实现
如有不对,不吝赐教
进入正题:
借助堆栈以非递归(循环)方式求解汉诺塔的问题(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; }
测试结果:
至于正确性,可以画图看下
- 【数据结构与算法】汉诺塔算法——C语言递归实现
- 【数据结构与算法】(五) c 语言递归与汉诺塔实现
- 【数据结构与算法】汉诺塔算法——java递归实现
- 【数据结构与算法】汉诺塔算法——C语言递归实现
- 数据结构基础(6)--递归和函数调用--汉诺塔问题C语言实现
- [算法]数据结构算法背包问题解法之递归解法,C语言实现
- 【数据结构与算法】递归汉诺塔
- 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,数据结构“栈”实现
- 【数据结构与算法】二分查找递归非递归实现
- 【数据结构与算法】二叉树 前序 中序 后序 非递归实现 极简
- 数据结构中关键路径算法的实现与应用
- 【数据结构与算法】第三章 表c实现
- 【数据结构与算法】【排序】快速排序的代码实现
- 数据结构之二叉树的非递归实现及“狡猾”的指针
- 【数据结构与算法】HashTable相关操作实现(附完整源码)
- 【数据结构与算法】【排序】直接插入排序的代码实现
- 算法与数据结构基础5:C++栈的简单实现
- 数据结构与算法学习笔记——链表部分实现(数组形式)
- 数据结构(六)——二叉树 前序、中序、后序、层次遍历及非递归实现 查找、统计个数、比较、求深度的递归实现
- 数据结构——算法之(012)( linux C 所有字符串操作函数实现)