首页 > 其他分享 >汉诺塔问题C语言递归

汉诺塔问题C语言递归

时间:2023-09-03 10:32:21浏览次数:41  
标签:Hanoi2 递归 int C语言 char 汉诺塔 盘子 移动

(汉诺塔问题C语言递归)

什么是汉诺塔问题

汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?(每次只能移动1个盘子,大盘子只能放在小盘子下面) 请添加图片描述

这里还有一个预言: 当所有的金片都从梵天穿好的那根针上移到另外一概针上时,世界就将在一声霹雳中消灭,梵塔、庙宇和众生都将同归于尽,也就是世界毁灭。

想要把64片金片从一根针上全部需要多长时间呢?也就是说世界毁灭会多长时间呢?让我们往下看

汉诺塔问题的实现

简单汉诺塔的推理

一个盘子

  • 当只有一个盘子的时候,很直接的看出,只需移动一次

在这里插入图片描述

两个盘子

  • 有两个盘子时,就需要借助第三个柱子才能实现

第一步:在这里插入图片描述 第二步:在这里插入图片描述 第三步: 最终:在这里插入图片描述

  • 如图,最终需要三步

三个盘子

第一步和第二步: 在这里插入图片描述 第三步:在这里插入图片描述 第四步: 在这里插入图片描述 第五步: 在这里插入图片描述 第六步,第七步: 在这里插入图片描述

  • 所以如图,三个盘子需要移动7次

汉诺塔问题的实现

偏数学方式的实现

以三个盘子为例: 先把三个盘子想象成一个盘加两个盘子(并且把这两个盘子看成整体) 在这里插入图片描述 先把这个整体移动到B柱上: 在这里插入图片描述 在把A柱上的那一个盘子移动到C主上 在这里插入图片描述 最后,再将两个盘子整体移动到C上在这里插入图片描述

  • 所以从始至终,一个盘和那两个盘子的整体只移动了三次,其中独自的那个盘子从A到C移动两次,两个盘子的整体移动了两次
  • 可以看出,两个盘子每次整体的移动都是一个含有两个盘子的汉诺塔问题

所以,假设n是圆盘的数量,T(n)是移动n个圆盘的移动次数。 当n=1时,T(1)=1 当n=2时,T(2)=2T(1)+1 当n=3时,T(3)=2T(2)+1 ……

就可以得出:在这里插入图片描述 也很容易得到公式: f(n) = 2^n-1

代码的实现:

int Hanoi(int n)
{
	if (n == 1)
	{
		return 1;
	}
	else
	{
		return 2*Hanoi(n - 1) + 1;
	}
}
int main()
{
	int n = 0;
	printf("输入A塔中盘子个数");
	scanf("%d", &n);
	printf("总共挪动的次数为:%d\n", Hanoi(n));
	return 0;
}

结果:在这里插入图片描述

偏过程方式的实现

从含有两个盘子的汉诺塔中可以看出来: 1号盘是借助于B柱,才最终到达A柱2号盘直接从A柱到C柱 在这里插入图片描述 再分析一下含有三个盘子的汉诺塔: 1号整体是借助柱到达B柱, 2号盘直接从A柱到C柱, 最终把整体借助A移动到C上 其中对于1号整体的移动就是含有两个盘的汉诺塔问题在这里插入图片描述>所以,以此类推,n个盘的汉诺塔,它的从上到下前n-1个盘是通过C柱到达B柱,最下面的一个盘是由A直接到C,最后再把整体借助A柱移动到C柱

代码实现:

void move(char x,char y)
{
	printf("从 %c 移动到 %c\n", x, y);
}


void Hanoi2(int n, char A, char B, char C)
{
	if (n == 1)       //只有一个盘子
	{
		ShowMove(A, C);  //直接移动即可
	}
	else
	{
		Hanoi2(n - 1, A, C, B);    //将上边n-1个盘子从a上借助c到达b
		ShowMove(A, C);    
		Hanoi2(n - 1, B,A,C);      //将上边n-1个盘子从b上借助a到达c
	}
}
int main()
{
	int n = 0;
	printf("输入A塔中盘子个数");
	scanf("%d", &n);
	Hanoi2(n, 'A', 'B', 'C');
	return 0;
}

代码解读: move(char,char)函数是为了从A柱上把最下面的盘子移动到C柱 void Hanoi2(int n, char a, char b, char c)中,形参n是盘子个数,a,b,c表示盘子在a上,借助b,最终到达c

结果: 在这里插入图片描述

  • 全部代码:
#include <stdio.h>
int Hanoi(int n)
{
	if (n == 1)
	{
		return 1;
	}
	else
	{
		return 2*Hanoi(n - 1) + 1;
	}
}

void ShowMove(char x,char y)
{
	printf("从 %c 移动到 %c\n", x, y);
}


void Hanoi2(int n, char a, char b, char c)
{
	if (n == 1)
	{
		ShowMove(a, c);
	}
	else
	{
		Hanoi2(n - 1, a, c, b);
		ShowMove(a, c);
		Hanoi2(n - 1, b,a,c);
	}
}
int main()
{
	int n = 0;
	printf("输入A塔中盘子个数");
	scanf("%d", &n);
	printf("总共挪动的次数为:%d\n", Hanoi(n));
	Hanoi2(n, 'A', 'B', 'C');
	return 0;
}

预言解读

根据前面得到的公式,当n为64时,需要移动2^64-1 = 18446744073709551615次 假如每秒钟一次 18446744073709551615÷31556952=584554049253.855年 移完这些金片需要5845亿年以上 所以到时候世界是否毁灭就不管你我的事啦! ~

标签:Hanoi2,递归,int,C语言,char,汉诺塔,盘子,移动
From: https://blog.51cto.com/u_16237630/7337951

相关文章

  • 通过c语言来实现斐波那契数列
    斐波那契数列是一组第一位和第二位为1,从第三位开始,后一位是前两位和的一组递增数列,像这样的:0、1、1、2、3、5、8、13、21、34、55......这个数列从第3项开始,每一项都等于前两项之和。以下通过c语言来实现这个程序#include<stdio.h>//1123581321345589intmain(){ /......
  • 递归乘法表
    #include<bits/stdc++.h>usingnamespacestd;voidno(inta,intb){ if(b<=9){ if(a<=b){ cout<<a<<"*"<<b<<"="<<a*b<<""; no(a+1,b); }else{ cout<<endl; no(1,b+1); } ......
  • 递归九九乘法表
    #include<iostream>usingnamespacestd;voidshow(inta,intb){ if(b<=9){ if(a<=b){ cout<<a<<"x"<<b<<"="<<a*b<<""; show(a+1,b); } cout<<endl; } show(1,b+1......
  • 递归 99乘法表
    1#include<iostream>2usingnamespacestd;3voidcheng(inta,intb){4if(a<=9){5if(b<=a){6cout<<a<<"x"<<b<<"="<<a*b<<"";7ch......
  • 九九乘法表(递归)
    #include<iostream>usingnamespacestd;voidf(inta,intb){ if(b<=9){ if(a<=b){ cout<<a<<"x"<<b<<"="<<a*b<<""; f(a+1,b); } cout<<endl; } f(1,b+1);}int......
  • 简单理解c语言指针
    &p(取地址)P*p(间接寻址) 假设p指向整数型变量a,那么可以理解为p等同于a的地址。*是间接寻址运算符,对p进行操作,找到p这个地址中所对应(放的)东西。也就是说,*p就是a。做个比喻,将*理解成取平方,而操作数p是地址,那么p的平方就是a,如2的平方就是4。(不过这里其实p不像是常量而更像变量x,......
  • C语言数组(9)--- 数组名(2)
    一.导入我们上篇文章讲了一维数组的数组名,接下来我们将介绍二维数组的数组名,我们先来猜一下以下代码执行的结果是多少:#include<stdio.h>intmain(void){ intarr[3][4]; intsz=sizeof(arr); printf("%d",sz); return0;}A.3B.4C.12D.48答案:D,解析:我们之前说过二维数组......
  • C语言读取csv文件并保存到二维数组
     #include<stdio.h>#include<string.h>#include<time.h>#defineMAXCHAR1024#defineMAXCOUNT1000000char*mat[MAXCOUNT][9];//如果放到main里面会有长度限制使应用程序退出,放在外面作为全局变量没有限制。intmain(){clock_tstart,end;start=clo......
  • 东方博宜OJ1009 数组逆序 C语言版
    题目描述给你 n 个整数,将其逆序输出。输入第一行一个整数 n (3≤n≤100)代表数的个数。第二行 n 个整数(空格隔开)(这些数在 0∼106 之间)。输出n 个整数(空格隔开)。样例输入3175输出571来源数组问题代码 #include<stdio.h>in......
  • 递归函数
    递归就是在函数内部调用自身。其实递归在很大程度上牺牲了空间换取了可读性。每次调用递归函数的时候都会创建一个函数栈,如果递归深度过大,则会造成溢出状况。原文中使用a,b=b,a+b方法求斐波那契数列,占用空间少,来回只有两个变量的空间占用,很方便。 斐波那契数列如果用递归方......