【C语言】用函数递归的方法解决汉诺塔问题

简介: 【C语言】用函数递归的方法解决汉诺塔问题

1.问题起源:

汉诺塔(又称河内塔)问题是印度的一个古老的传说。开天辟地的神勃拉玛在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。面对庞大的数字(移动圆片的次数)18446744073709551615,看来,众僧们耗尽毕生精力也不可能完成金片的移动。后来,这个传说就演变为汉诺塔游戏。

2.汉诺塔游戏规则:

简单来说,就是把a柱上的n个圆盘,通过b柱作为辅助全部搬运到c柱上去。在搬运的过程中一次只能搬运一个圆盘,而且大圆盘不能放到小圆盘上面。

3.递归是什么?

要用递归的方法解决这个问题,我们首先要知道何为递归。

递归就是一个函数在它的函数体内调用它自身。执行递归函数将反复调用其自身,每调用一次就进入新的一层。递归函数必须有结束条件。

当函数在一直递推,直到遇到墙后返回,这个墙就是结束条件。

所以递归要有两个要素,结束条件与递推关系。

4.问题分析:

我们很容易知道:

当n=1时,我们直接将盘子从a柱移到c柱便解决了问题。

当n=2时,我们可以先把a柱上的第一个盘子移动到b柱(a柱最上面的盘子编号为1,向下依次递增),然后将a柱上的第二个盘子移动到c柱,再将b柱上的盘子移动到c柱即可。

但是当n的值为3及以上时问题便变得麻烦起来了。那么我们能否将后面复杂的问题化简为前面简单的两种情况呢?

答案是肯定的,这也是函数递归的目的:将复杂的问题简单化。

代码实现:

我们可以先通过动图先来看一下具体怎么实现。

汉诺塔问题(函数递归)

我们只需将盘子个数为n的分为两类解决即可:

当n=1时,将盘子从a->c即可。

当n>1时,将a柱上的n-1个盘子移动到b柱上,再将a柱上剩下的一个(也就是第n个)移动到c柱上,然后将b柱上的n-1个移动到,c柱上即可。(记住我们这里是将n-1个盘子看为一个整体)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//汉诺塔问题
int count = 0;
void move(int n, char a, char b, char c)
{
  if (n == 1)
    printf("第%d次:%c->%c\n", ++count, a, c);
  else
  {
    move(n - 1, a, c, b);
    printf("第%d次:%c->%c\n", ++count, a, c);
    move(n - 1, b, a, c);
  }
}
int main()
{
  int n = 0;
  printf("请输入圆盘的个数:\n");
  scanf("%d", &n);
  move(n, 'a', 'b', 'c');
  printf("共移动了%d次\n", count);
  return 0;
}

测试结果如下:

5.结果分析:

我们会发现,当圆盘为1的时候只用移动一次,但当圆盘为4时,要15次,可想而知,这个问题设计计算量是很大的,而且还会发现,当圆盘个数特别大时,电脑运算速度会明显降低,因为计算机要通过不停进行递归,所以递归只是解决题目的一种方法。在我看来汉诺塔问题包括大多数能用函数递归解决的问题都需要我们有一种能力,那就是将一些东西当作一个整体来看待。比如汉诺塔问题中我们就要将n-1看作一个整体,如果不能做到有这种理解能力,那么将很难理解如何用函数递归解决汉诺塔问题。

相关文章
|
8月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
1465 0
|
10月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
450 15
|
人工智能 Java 程序员
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
613 1
一文彻底搞清楚C语言的函数
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
780 16
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
678 3
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
817 2
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
653 1
|
存储 C语言
C 语言函数完全指南:创建、调用、参数传递、返回值解析
函数是一段代码块,只有在被调用时才会运行。 您可以将数据(称为参数)传递给函数。 函数用于执行某些操作,它们对于重用代码很重要:定义一次代码,并多次使用。
573 3
|
C语言
C语言---函数---知识点总结(三)------函数的返回值类型
C语言---函数---知识点总结(三)------函数的返回值类型
|
C语言
C语言函数返回值详解
本文详细解析了C语言中函数返回值的概念与应用。从函数的基本定义入手,深入探讨了不同类型返回值的作用及意义,并提供了实用的编程示例,帮助读者更好地理解和使用函数返回值。通过本文,你将掌握如何有效利用返回值优化代码结构与功能实现。
1664 2