3-2 汉诺塔的非递归实现

  汉诺塔实现的基本思路是:不断将n个盘的汉诺塔问题转换为2个(n-1)个盘的汉诺塔问题,用递归实现比较好理解。设n盘问题为(n, a, b, c),其中参数如下结构体所定义,第一个参数表示需要移动的盘子的数量,第二个参数表示n个盘子起始所在柱子a, 第三个参数表示会被借用的柱子b, 第四个参数表示这 n个盘子所在的目标柱子c。

递归思路

假设(n, a, b, c)表示把 a柱子上的n个盘借助b柱子移动到 c 柱子上,这个问题的递归求解方式是

先把 a 柱子的(n-1)盘子借助c柱子移动到b柱子上(n-1, a, c, b),

然后把 a 柱子剩下的一个盘子移动到 c 柱子上(1, a, b, c),

最后把 b 柱子上的(n-1)个盘子移动到 c 柱子上(n-1, b, a, c)

则问题求解可转换为对(n - 1, a, c, b)、(1, a, b, c)、(n - 1, b, a, c)这三个问题的求解,其中(1, a, b, c)不需要递归,可直接实现,将n个盘的汉诺塔问题转换为2个(n-1)个盘的汉诺塔问题,然后使用递归将(n-1)盘问题转换成(n-2)盘问题,直到盘数为1

非递归的方式

  递归方式本质上使用栈来实现的,所以如果采用非递归的方式也是使用栈来辅助实现。

  但是若是用堆栈来实现的话,当将分解出的上述三个问题压入栈时,应该按照“需要先求解的问题后压入”的顺序,也就是压入顺序为:(n - 1, b, a, c), (1, a, b, c), (n - 1, a, c, b).

1 typedef struct {  //汉诺塔问题的结构类型
2     int N;
3     char A;        //起始柱
4     char B;        //借助柱
5     char C;        //目标柱
6 
7 }ElementType;    //汉诺塔问题的结构类型

 

 1 //借助栈的非递归实现
 2 void Hanoi(int n)
 3 {
 4     ElementType P, toPush;
 5     Stack S;
 6 
 7     P.N = n; P.A = 'a'; P.B = 'b'; P.C = 'c';
 8     S.top = -1;
 9 
10     Push(&S, P);
11     while (S.top != -1)        //当堆栈不为空时
12     {
13         P = Pop(&S);
14         if (P.N == 1)
15             printf("%c  -> %c\n", P.A, P.C);
16         else
17         {
18             toPush.N = P.N - 1;
19             toPush.A = P.B; toPush.B = P.A; toPush.C = P.C;
20             Push(&S, toPush);        //将第二个待解子问题(n - 1, b, a, c)入栈
21             toPush.N = 1;
22             toPush.A = P.A; toPush.B = P.B; toPush.C = P.C;
23             Push(&S, toPush);        //将可直接求解的子问题(1, a, b, c)入栈
24             toPush.N = P.N - 1;
25             toPush.A = P.A; toPush.B = P.C; toPush.C = P.B;
26             Push(&S, toPush);        //将第一个待解子问题(n - 1, a, c, b)入栈
27         }
28     }
29 }

下面是栈的实现和主函数:

 1 #include <stdio.h>
 2 #define MaxSize 100
 3 
 4 typedef struct {
 5     ElementType Data[MaxSize];
 6     int top;
 7 }Stack;        //堆栈的标准定义
 8 
 9 void Push(Stack *PtrS, ElementType item)
10 {
11     //入栈操作
12     if (PtrS->top == MaxSize)
13     {
14         printf("The stack is full!\n");
15         return;
16     }
17     else
18     {
19         PtrS->Data[++(PtrS->top)] = item;
20         return;
21     }
22 }
23 
24 ElementType Pop(Stack *PtrS)
25 {
26     if (PtrS->top == -1)
27     {
28         printf("The stack is empty!\n");
29         return ERROR;        //ERROR是ElementType的特殊值,标志错误
30     }
31     else
32     {
33         PtrS->top--;
34         return (PtrS->Data[PtrS->top + 1]);        //或者是return PtrS->Data[PtrS->top--];
35     }
36 }
37 
38 int main()
39 {
40     int n;
41     ERROR.N = -1;    //ERROR是ElementType的特殊值,标志错误
42     scanf_s("%d", &n);
43     Hanoi(n);
44     return 0;
45 }

 

上一篇:centos安装redis


下一篇:(C语言)堆栈顺序存储源码(包含测试)