汉诺塔递归与非递归的实现
问题描述:
汉诺塔问题源自印度一个古老的传说,印度教的“创造之神”梵天创造世界时做了 3 根金刚石柱,其中的一根柱子上按照从小到大的顺序摞着 64 个黄金圆盘。梵天命令一个叫婆罗门的门徒将所有的圆盘移动到另一个柱子上,移动过程中必须遵守以下规则:
1、每次只能移动柱子最顶端的一个圆盘;
2、每个柱子上,小圆盘永远要位于大圆盘之上;
输入:一个正整数N,为起始柱上的盘数。
输出:每一步移动操作(%c -> %c格式输出)。
算法优化:无。
递归算法思路:
(1)先将 n - 1 个盘子从 a 通过 c 移动到 b 。
(2)再将最后一个盘子从 a 移动到 c 。
(3)最后将 n - 1 个盘子从 b 通过 a 移动到 c 。
#include <stdio.h>
void hanoi(int num, char sou, char tar,char aux) {
//统计移动次数
static int i = 1;
//如果圆盘数量仅有 1 个,则直接从起始柱移动到目标柱
if (num == 1) {
printf("%c -> %c\n", sou, tar);
i++;
}
else {
//递归调用 hanoi() 函数,将 num-1 个圆盘从起始柱移动到辅助柱上
hanoi(num - 1, sou, aux, tar);
//将起始柱上剩余的最后一个大圆盘移动到目标柱上
printf("%c -> %c\n", sou, tar);
i++;
//递归调用 hanoi() 函数,将辅助柱上的 num-1 圆盘移动到目标柱上
hanoi(num - 1, aux, tar, sou);
}
}
int main()
{
//以移动 N 个圆盘为例,起始柱、目标柱、辅助柱分别用 A、B、C 表示
int n;
scanf("%d", &n);
hanoi(n, 'A', 'B', 'C');
return 0;
}
输入:
3
输出:
非递归算法思路:
1.将n-1个盘子由a柱借助c柱移动到b柱
2.将最下面的盘子由a柱直接移动到c柱
3.将那n-1个盘子在由b柱借助a柱移动到c柱
因为这个是出栈时的操作,所以入栈时要到着写
#include<stdio.h>
#include <stdlib.h>
#define MaxSize 100
typedef struct{
int N;
char A; //起始柱
char B; //借助柱
char C; //目标柱
}ElementType;
typedef struct {
ElementType Data[MaxSize];
int top;
}Stack;//汉诺塔问题的结构类型
void Push(Stack *PtrS, ElementType item){
//入栈操作
if (PtrS->top == MaxSize)
{
printf("The stack is full!\n");
return;
}
else
{
PtrS->Data[++(PtrS->top)] = item;
return;
}
}
ElementType Pop(Stack *PtrS){
if (PtrS->top == -1)
{
printf("The stack is empty!\n");
exit(1); //直接终止程序,一般不会出现这个错误
}
else
{
PtrS->top--;
return (PtrS->Data[PtrS->top + 1]); //或者是return PtrS->Data[PtrS->top--];
}
}
//借助栈的非递归实现
void Hanoi(int n){
ElementType P, toPush;
Stack S;
P.N = n; P.A = 'a'; P.B = 'b'; P.C = 'c';
S.top = -1;
Push(&S, P);
while (S.top != -1) //当堆栈不为空时
{
P = Pop(&S);//出栈
if (P.N == 1)//当只剩一个盘子时,直接由当前柱移动到目的柱
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);
if (n <= 0)return 0;
else Hanoi(n);
}
输入:
3
输出:
总结:
汉诺塔其实是一个简单的递归问题,让我们更加深刻的了解递归的应用。但是如果采用非递归去实现就会考查到堆栈的运用,这样反而弄得更加的复杂化。