C语言超详细讲解递归算法汉诺塔

目录
  • 题目描述
  • 画图分析
  • 思路总结
  • 代码实现
  • 总结

题目描述

汉诺塔问题起源于一个传说

汉诺塔又被称为河内塔,传说,在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。

印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。 不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。 僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

我们现在要研究的就是在不同情况下盘子的移动顺序和移动的次数。

画图分析

由简到繁,我们先从最简单的情况来分析:

~~只有一个盘子的时候:

只有一个盘子我们直接把它从A柱移到C柱就行,此时移动次数是1,移动顺序是 A->C

~~有两个盘子的时候:

有两个盘子的时候我们需要先将较小的盘子移动到B柱,然后将较大的盘子移动C柱,再将B柱上的盘子移动到C柱;此时移动次数是3,移动顺序是 A->B A->C B->C

~~有三个盘子的时候:

有三个盘子的时侯,我们把最小的盘子命名为1,中间的为2,最大的为3,那么移动顺序应该是:1号移到到C柱,2号移动到B柱,1号移动到B柱,3号移动到C柱,1号移动到A柱,2号移动到C柱,1号移动到C柱;一共移动7次,移动顺序是A->C A->B C->B A->C B->A B->C A->C

A->C A->B C->B

A->C B->A

B->C A->C

思路总结

在上面的移动过程中,B柱始终起着中转的作用,我们我们可以理解为:

  • A柱:起始柱
  • B柱:中转柱
  • C柱:目标柱

同时,我们发现一个盘子时需要移动一次,两个盘子时需要移动3次,3个盘子时需要移动7次,所以总结规律:n个盘子需要移动的次数是 2n-1 次。

其次,我们可以把上面的移动过程简化为三个步骤:

  • 把n-1个盘子通过C柱移到B柱上。
  • 把A柱上的最后一个盘子移动到C柱上。
  • 把n-1个盘子通过A柱移动到C柱上。

比如,上面盘子个数为三的时候,我们可以分解为:第一步:1号移到到C柱,2号移动到B柱,1号移动到B柱;第二步:3号移动到C柱;第三步:1号移动到A柱,2号移动到C柱,1号移动到C柱。

所以,n个盘子的移动顺序为:

1、把n-1个盘子通过C柱移到B柱上。

2. 把A柱上的最后一个盘子移动到C柱上。

3. 把n-1个盘子通过A柱移动到C柱上。

代码实现

#include<stdio.h>

//Move函数,用来移动盘子,pos1表示起始柱,pos2表示目标柱
void Move(char pos1, char pos2)
{
	printf("%c->%c ", pos1, pos2);  //把pos1的盘子移动到pos2
}

//Hanoi函数,用来实现汉诺塔,其中n表示盘子的个数,pos1表示起始柱,pos2表示中转柱,pos3表示目标柱
void Hanoi(int n, char pos1, char pos2, char pos3)
{
	if (1 == n)  //当n==1时,直接把盘子从A柱移动到C柱
	{
		Move(pos1, pos3);
	}
	else   //当n不等于1时,分三步走
	{
		//第一步:将n-1个盘子通过C柱移动到B柱,此时C柱时中转柱,B柱是目标柱
		Hanoi(n - 1, pos1, pos3, pos2);
		//第二步:把A柱最后一个盘子直接移动到C柱
		Move(pos1, pos3);
		//第三步:将n-1个盘子通过A柱移动到C柱,此时B柱是起始柱,A柱是中转柱,C柱是目标柱
		Hanoi(n - 1, pos2, pos1, pos3);
	}
}
int main()
{
	//定义一个变量来表示盘子的个数
	int n = 0;
	//定义三个字符变量来表示三根柱子
	char pos1 = 'A';
	char pos2 = 'B';
	char pos3 = 'C';
	//调用hanoi函数
	Hanoi(1, pos1, pos2, pos3);  //n为1
	printf("\n");
	Hanoi(2, pos1, pos2, pos3);  //n为2
	printf("\n");
	Hanoi(3, pos1, pos2, pos3);  //n为3
	printf("\n");
	Hanoi(4, pos1, pos2, pos3);  //n为4
	printf("\n");
	return 0;
}

总结

知道了汉诺塔的逻辑后,我们重新回到这个问题,我们发现,要把64片金片全部挪完需要挪动 264-1 次,假设这个僧侣一秒钟移动一次,那么一共要挪 (264-1) / 3600 / 24 / 365 = 584,942,417,355(年),那时候地球已经毁灭也不是没有可能,哈哈。

到此这篇关于C语言超详细讲解递归算法汉诺塔的文章就介绍到这了,更多相关C语言汉诺塔内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言递归思想实现汉诺塔详解

    目录 1.递归思想简介 2.汉诺塔问题 3.汉诺塔递归的c语言实现 总结 1.递归思想简介 在c语言中,程序调用自身的编程技巧称为递归( recursion). 递归的定义看上去似乎很抽象,使用代码描述能够让人容易理解,下面是一个函数递归的例子. /* 递归求n的阶乘 */ int factorial(int n) //定义一个求阶乘的函数叫做factorial(),需要一个整形参数,返回一个整形值 { if (n <= 1) //递归结束的条件 { return 1; } else { ret

  • C语言编程递归算法实现汉诺塔

    汉诺塔 法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针.印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔.不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面.僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔.庙宇和众生也都将同归于尽. 这个传说挺有意思的,这个传说

  • C语言递归之汉诺塔和青蛙跳台阶问题

    递归就是一个函数执行过程中调用自己,在c语言中有很多关于递归的经典问题,例如:斐波那契数列问题.汉诺塔问题等,在研究递归问题时我们要注意三点: 1.递归的结束条件 2.递归在每次进行过程中,都得离条件越来越近 3.相邻两次递归调用之间的关联关系 汉诺塔问题: 有三根杆子A, B, C.A杆上有N个(N > 1)穿孔圆盘, 盘的尺寸由下到上依次变小.要求按下列规则将所有圆盘移至C杆: 1.每次只能移动一个圆盘: 2.大盘不能叠在小盘上面,可将圆盘临时置于B杆, 也可将从A杆移出的圆盘重新移回A杆,

  • C语言用递归函数实现汉诺塔

    目录 汉诺塔(Hanoi)是什么? 那么,C语言如何实现汉诺塔呢? 汉诺塔的基本思路是: 具体代码见下(注意点在代码下面): 总结 汉诺塔(Hanoi)是什么? 一个简单的汉诺塔就如上图所示,有三个放置点,放置物必须遵循上小下大的规则,依次将1中的放置物全部放置到3中.就比如该图中有4个放置物,若将A上的放置物全部移至C上,具体的步骤是:A->B A->C B->C A->B C->A C->B A->B A->C B->C B->A C->

  • C语言超详细讲解递归算法汉诺塔

    目录 题目描述 画图分析 思路总结 代码实现 总结 题目描述 汉诺塔问题起源于一个传说 汉诺塔又被称为河内塔,传说,在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针. 印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔. 不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面. 僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而

  • C语言 超详细讲解算法的时间复杂度和空间复杂度

    目录 1.前言 1.1 什么是数据结构? 1.2 什么是算法? 2.算法效率 2.1 如何衡量一个算法的好坏 2.2 算法的复杂度 2.3 复杂度在校招中的考察 3.时间复杂度 3.1 时间复杂度的概念 3.2 大O的渐进表示法 3.3 常见时间复杂度计算举例 4.空间复杂度 5. 常见复杂度对比 1.前言 1.1 什么是数据结构? 数据结构(Data Structure)是计算机存储.组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合. 1.2 什么是算法? 算法(Algorit

  • C语言 超详细讲解链接器

    目录 1 什么是链接器 2 声明与定义 3 命名冲突 3.1 命名冲突 3.2 static修饰符 4 形参.实参.返回值 5 检查外部类型 6 头文件 1 什么是链接器 典型的链接器把由编译器或汇编器生成的若干个目标模块,整合成一个被称为载入模块或可执行文件的实体–该实体能够被操作系统直接执行. 链接器通常把目标模块看成是由一组外部对象组成的.每个外部对象代表着机器内存中的某个部分,并通过一个外部名称来识别.因此,==程序中的每个函数和每个外部变量,如果没有被声明为static,就都是一个外部

  • C语言 超详细讲解库函数

    目录 1 返回整数的getchar函数 2 更新顺序文件 3 缓冲输出与内存分配 4 库函数 练习 1 返回整数的getchar函数 代码: #include<stdio.h> int main() { char c; while((c = getchar())!=EOF)//getchar函数的返回值为整型 putchar(c); return 0; } 上述代码有三种可能: 某些合法的输入字符在被"截断"后使得c的取值与EOF相同,程序将在复制的中途停止. c根本不可能

  • C语言超详细讲解字符串相乘

    目录 前言 一. 分析思路 二.使用步骤 1.代码如下 2.memset函数 三.总结 前言 我们已经知道,正常的两位整形数据通过*相乘,C语言中int为4字节,32bit(字节),其机器码第一位为符号位,余下31位表示数字,表示范围:-2^31(-2147483648)~2^31-1(2147483647),但超过了这个范围我们该如何做呢? 提示:将数字以字符串的形式进行操作 一. 分析思路 示例: 我们把每一个数都看成是一个字符串,每一个元素为十进制数字所对应的字 符,由于是后面的元素先进行

  • C语言超详细讲解排序算法上篇

    目录 1.直接插入排序 2.希尔排序(缩小增量排序) 3.直接选择排序 4.堆排序 进入正式内容之前,我们先了解下初阶常见的排序分类 :我们今天讲前四个! 1.直接插入排序 基本思想:当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排 序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移! 直接插入排序的特性总结: 1. 元素集

  • C语言超详细讲解栈与队列实现实例

    目录 1.思考-1 2.栈基本操作的实现 2.1 初始化栈 2.2 入栈 2.3 出栈 2.4 获取栈顶数据 2.5 获取栈中有效元素个数 2.6 判断栈是否为空 2.7 销毁栈 3.测试 3.1测试 3.2测试结果 4.思考-2 5.队列的基本操作实现 5.1 初始化队列 5.2 队尾入队列 5.3 队头出队列 5.4 队列中有效元素的个数 5.5 判断队列是否为空 5.6 获取队头数据 5.7 获取队尾的数据 5.8 销毁队列 6.测试 6.1测试 6.2 测试结果 1.思考-1 为什么栈用

  • C语言超详细讲解轮转数组

    目录 题目描述 实例 解题思路 1. 先整体逆转 2.逆转子数组[0, k - 1] 3.逆转子数组[k, numsSize - 1] 易错点 代码 题目描述 给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数.OJ链接 实例 1.实例1 输入: nums = [1,2,3,4,5,6,7], k = 3输出: [5,6,7,1,2,3,4]解释:向右轮转 1 步: [7,1,2,3,4,5,6]向右轮转 2 步: [6,7,1,2,3,4,5]向右轮转 3 步: [5,6,7

  • C语言超详细讲解数据结构中双向带头循环链表

    目录 一.概念 二.必备工作 2.1.创建双向链表结构 2.2.初始化链表 2.3.动态申请节点 2.4.打印链表 2.5.销毁链表 三.主要功能 3.1.在pos节点前插入数据 尾插 头插 3.2.删除pos处节点数据 尾删 头删 3.3.查找数据 四.总代码 List.h 文件 List.c 文件 Test.c 文件 五.拓展 一.概念 前文我们已经学习了单向链表,并通过oj题目深入了解了带头节点的链表以及带环链表,来画张图总体回顾下: 在我们学习的链表中,其实总共有8种,都是单双向和带不带

  • C语言超详细讲解栈的实现及代码

    目录 前言 栈的概念 栈的结构 栈的实现 创建栈结构 初始化栈 销毁栈 入栈 出栈 获取栈顶元素 获取栈中有效元素个数 检测栈是否为空 总代码 Stack.h 文件 Stack.c 文件 Test.c 文件 前言 栈的概念 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作.进行数据插入和删除操作的一端称为栈顶,另一端称为栈底.栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则.有点类似于手枪弹夹,后压进去的子弹总是最先打出,除非枪坏了. 压栈:栈的插入

随机推荐