汉诺塔问题

最近学习递归的时候看到了这样一个问题,叫做汉诺塔问题,是一个很经典的递归问题,下面是它的原题目的描述:

/****这个问题来源于印度。有三个金刚石塔,第一个从小到大摞着64片黄金圆盘。现在把圆盘按大小顺序重新摆放在最后一个塔上。并且规定,在小圆盘上不能放大圆盘,在三个塔之间一次只能移动一个圆盘。***/

为了能够直观地看看这个问题,这里我们画一个图

我们初始放盘子的柱子A叫做初始柱,C为我们的目标柱,B为我们的中转柱,我们要借助B柱把A上的盘子转移到C柱上

我们要实现这样的过程,我们要确保我们第一个放在C柱上的盘子应该是最大的那个,我们总共有n个盘子,那么我们就要先把最大的盘子上面的n-1个盘子转移到B柱(中转柱)上

我们就把刚刚的问题转化成了细分的小问题,就是先把n-1个上方的小盘子放在B柱上,然后把最下面的最大的盘子放在C柱上(目标柱),再把剩下的n-1个小盘子放在C柱上
 

即:此次目标:C柱

        1.上方n-1盘从A——>B

        2.下方的最大n盘从A——>C

        3.刚刚放在B柱上的n-1盘从B——>C

——————————————————分割线——————————————————————

像这样再细分,把(n-1)个小盘子分成这部分盘子最下面的那个盘子和上面的n-2个盘子,那么我们就可以继续刚刚的操作这次我们上面的n-1盘的目标柱是B柱

即:此次目标:B柱

        1.上方n-2盘从A———>C

        2.下方第n-1盘从A———>B

        3.把刚刚放在C柱上的n-2个盘放回B柱

这里就是我们对上方的n-1盘的移动处理

当然,我们的套娃过程还没有结束,我们还要用别的方式将这部分的上方n-3的部分再次进行移动

——————————————————分割线—————————————————————

总而言之,不管n是多少,我们执行的过程都是一个模版的,那么我们如果要使用递归实现代码,我们就要设置停止递归的条件

什么时候递归停止套娃呢?我们可以发现,我们将一摞盘子移动到目标柱子上,需要借助中转柱的原因是我们最大的那个盘子上面还有小盘子,所以我们要使用中转柱执行把小盘放在一边然后移动下面的盘子的动作

如果我们只有一个盘子呢?很明显,这个时候我们就可以忽略这个中转柱,从而直接把我们的盘子从起始柱直接放到目标柱上。

那么我们套娃的停止条件就是n=1

———————————————————分割线—————————————————————

需要用代码生动形象表示出这个过程,我们就可以这样做:

定义一个print函数,用来表示把x柱子最上方的盘子放在y柱上,即:

void print(char x,char y)
{
	printf("%c-->%c\n",x,y);//表示把x柱子最上方的盘子放在y柱上	
} 

设置一个move函数参数有 :盘子的数量n,起始柱的编号,中转柱的编号,目标柱的编号

再引入我们刚刚的分析

即:此次目标:C柱

        1.上方n-1盘从A——>B

        2.下方的最大n盘从A——>C

        3.刚刚放在B柱上的n-1盘从B——>C

然后我们就可以写出函数:

void move(int n,	char start, char temp,	char end)// 参数分别为 	
//		圆盘初始数量;    初始杆;	 中转杆;   目标杆 
{
	if(n==1)
		 print(start,end);//如果只有一个圆盘就可以直接把它放在目标杆上 
	else 
	{
		move(n-1,start,end,temp);//如果要移动最下面的圆盘就要把上面的圆盘移动到中转杆上
		print(start,end);//把最大的圆盘移动到目标杆上
		move(n-1,temp,start,end);//把刚刚中转盘上面的圆盘都移到目标盘上 
	}
}

这样我们就完成了对这个题目的解读

———————————————————————————————————————————

那么,我们除了可以进行盘子路径的演示,我们是不是还可以对我们移动盘子的次数进行计算呢?

那么我们就可以定义一个函数movecount,我们不需要对路径研究,我们就只要传入盘子的个数n,下面我们就要进行规律的探寻:

首先我们要知道我们的n和我们移动的次数之间有什么关系,这个时候我们不好思考的话,我们就可以一个一个罗列出来

                盘子个数                         移动次数

                        1                                        1

                        2                                        3

                        3                                        7

                        4                                       15

                        5                                       31 

这样我们就可以发现除了第一次是1以外,剩下的每一次移动次数都会等于它们盘子减一之后乘2再加上一的值。用movecount表示的话就是,movecount(n)=2*movecount(n-1)-  1

那么我们就可以使用这个函数关系进行递归计算,当然也可以用其他方法,这里就不一一举例了

void movecout(int n)
{
    int ret;//定义返回值
    if(n==1) ret = 1;//如果为一则只进行一次移动,即n=1为函数的终止条件
    else 
        ret = movecount(n)=2*movecount(n-1)-  1;//如果大于1就进行函数关系式的递推
     return ret;//返回值
}

这样我们就完成了汉诺塔问题的整体思路,快去试试吧!

  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值