文章目录
- 前言
- 汉诺塔问题的起源:
- 问题分析:
- 总结:
- 代码实现:
前言
- 🛕“汉诺塔问题”是运用递归思想解决问题的经典例题,非常值得我们去深入地去理解递归的思想!
- 递归的核心思想就是把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
汉诺塔问题的起源:
汉诺塔(Tower of Hanoi)
,又称河内塔
,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。不论白天黑夜,总有一个僧侣在移动这些圆盘,一次只移动一个,小的圆盘必须在大的上面。僧侣们预言,当所有的圆盘都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而庙宇和众生也都将同归于尽……
动态图演示:
问题分析:
设左为A
,中间为B
,右为C
。
1、当柱子上只有一个圆盘时(即n=1),就非常简单,直接从左边(A)
移动到右边(C)
即可。
2、当柱子上有两个圆盘时(即n=2)
- 第一步先把小圆盘从
左(A)
移动到中间(B)
- 第二步再将大圆盘从左(A)移动到
右边(C)
- 第三步将在
中间(B)
的小圆盘移动到右(C)
3、当柱子上有三个圆盘时(即n=3),这个时候如果我们一个一个地去分析,情况就开始变得有点复杂了。
- 第一步先把上面两个从
左(A)
先移动到中间(B)
(它俩怎样移动先不考虑) - 第二步将底下最大的圆盘移动到
右边(C
- 第三步再将
中间(B)
的两个圆盘移动到右边(C
) - 其中第二步可以直接实现,而第一步和第三步还需继续递归
- 第一步中在
左(A)
的两个圆盘通过右(C)
移动到中间(B)
- 第三步中在
中间(B)
的两个圆盘通过左(A)
移动到右(C)
4、顺着这样的思路
- 如果柱子上面有n个圆盘,依然可以先把上面的
n-1个看作一个整体
,通过右(C)
移动到中间(B)
- 把第n个圆盘(最底下的圆盘)移动到
右边(C)
- 然后
中间(B)
n-1个圆盘又可以把上面的n-2个圆盘继续用递归的思想
继续拆分,直到圆盘全部移动到右边(C)
总结:
1、第一步移动n-1
小盘子从左(A)移动到中间(B)(又可以递归)
出第一、二、三步,一直递推,直到左(A)上除了底下那个外,其它全部移动到中间(B)
2、第二步移动第n
个小盘子从左(A)移动到右(C)(直接实现)
3、第三步移动n-1
小盘子从中间(B)移动到右(C)(又可以递归)
出第一、二、三步,一直递推,直到中间(B)上的圆盘全部的圆盘全部移动到右(C),结束!
- 把n-1个圆盘看作为一个
整体
,再把n-2个圆盘看作一个整体,再把…,直到达到结束条件! - 递归就是要
大化小,繁化简
。 - 运用递归思想就是让一个函数在它的函数体内调用它自己。
- 递归会使得函数反复调用自身,每次调用都会在
函数栈帧上开辟一块空间
,一直递推
,直到遇到结束条件。 - 递归有两个条件,
递推关系和结束条件
。
代码实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void Hanoi(int n, char A, char B, char C)//将n个圆盘从左边(A)借助中间(B)全部移动到右边(C)
{
if (n == 1)//当只有1个圆盘时
printf("%c->%c\n", A, C);//直接将左边(A)的圆盘移动到右边(C)
else//当n>=2时
{
Hanoi(n - 1, A, C, B);//将左边(A)上面的n-1个圆盘借助右边(C)移动到中间(B),
//一直递推,直到左(A)上除了底下那个外,其它全部移动到中间(B)
printf("%c->%c\n", A, C);//将左边(A)上剩下的1个圆盘移动到右边(C)
Hanoi(n - 1, B, A, C);//将中间(B)上的n-1个圆盘借助左边(A)移动到右边(C),
//一直递推,直到中间(B)上的圆盘全部的圆盘全部移动到右(C),结束!
}
}
int main()
{
int n = 0;
scanf("%d", &n);//输入n个圆盘
Hanoi(n, 'A', 'B', 'C');
return 0;
}