汉诺塔问题的递归和非递归算法

带你理解 Hanoi 汉诺塔递归算法 一. 由游戏引发的 Hanoi 问题 汉诺塔是根据一个传说形成的一个问题。汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着 64 片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。 二. 一种数学问题 我们... 阅读详情

       汉诺塔问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

如果考虑一下把64片金盘,由一根柱子上移到另一根柱子上,并且始终保持上小下大的顺序。这需要多少次移动呢?这里需要递归的方法。假设有n片,移动最少次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此后不难证明f(n)=2^n-1。

在本文中,将讨论用递归和非递归的方法来解决汉诺塔问题。

1、 通过递归实现汉诺塔问题的求解

设f(n)为将n片圆盘所在塔全部移动到另一塔最少总次数;由递归算法可知:f(1) = 1;当n>1时,f(n)   = f(n-1) +  1 + f(n-1)。f(n) = 把上面n-1片圆盘移动到中间塔最少总次数f(n-1) + 把第n片圆盘移动到目标塔+ 把中间盘的n-1片圆盘移动到目标塔最少总次数为f(n-1)。由数学计算可得:f(n)=2^n-1。(n>0)。此算法的递归代码实现如下所示:

#include <fstream>
#include <iostream>
#include<time.h>
using namespace std;
void Move(int n,char x,char y)
{
   cout<<"把"<<n<<"号从"<<x<<"挪动到"<<y<<endl;
}
void Hannoi(int n,char a,char b,char c)
{
      if(n==1)
              Move(1,a,c);
    else
    {
          Hannoi(n-1,a,c,b);
            Move(n,a,c);
            Hannoi(n-1,b,a,c);
    }
}
int main()
{
  int n;
  cout<<"请输入要求解的汉诺塔的阶数: ";
  cin>>n;
  clock_t start,finish;
  start = clock();
    cout<<"以下是7层汉诺塔的解法:"<<endl;
    Hannoi(n,'a','b','c');
    cout<<"输出完毕!"<<endl;
  finish = clock();
  printf("解决此 %d 阶汉诺塔所需的时间为:%.2f ms\n",n,(double)(finish-start));
  system("pause");
    return 0;
}

2、 通过非递归的思想来实现汉诺塔问题的求解

汉诺塔的非递归算法描述如下:

首先容易证明,当盘子的个数为n时,移动的次数应等于2^n - 1。

一位美国学者发现一种出人意料的方法,只要轮流进行两步操作就可以了。

首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子A上。

根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C;

若n为奇数,按顺时针方向依次摆放 A C B。

(1)按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;

若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A。

(2)接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。

即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘

这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。

(3)反复进行(1)(2)操作,最后就能按规定完成汉诺塔的移动。

该算法的实现代码如下:

#include <iostream>
#include<time.h>
using namespace std;
//圆盘的个数最多为64
const int MAX = 64;
//用来表示每根柱子的信息
struct st{
     int s[MAX]; //柱子上的圆盘存储情况
     int top; //栈顶,用来最上面的圆盘
     char name; //柱子的名字,可以是A,B,C中的一个
     int Top()//取栈顶元素
     {
           return s[top];
     }
     int Pop()//出栈
     {
           return s[top--];
     }
     void Push(int x)//入栈
     {
           s[++top] = x;
     }
} ;
 
long Pow(int x, int y); //计算x^y
void Creat(st ta[], int n); //给结构数组设置初值
void Hannuota(st ta[], long max); //移动汉诺塔的主要函数
int main(void)
{
     clock_t start,finish;
           int n;
           cout<<"请输入汉诺塔的阶数:";
     cin >> n; //输入圆盘的个数
           start = clock();
     st ta[3]; //三根柱子的信息用结构数组存储
     Creat(ta, n); //给结构数组设置初值
     long max = Pow(2, n) - 1;//动的次数应等于2^n - 1
     Hannuota(ta, max);//移动汉诺塔的主要函数
           finish = clock();
           printf("解决此 %d 阶汉诺塔所需的时间为:%.2f ms\n",n,(double)(finish-start));
     system("pause");
     return 0;
}
void Creat(st ta[], int n)
{
     ta[0].name = 'A';
     ta[0].top = n-1;
    //把所有的圆盘按从大到小的顺序放在柱子A上
     for (int i=0; i<n; i++)
           ta[0].s[i] = n - i;
     //柱子B,C上开始没有没有圆盘
     ta[1].top = ta[2].top = 0;
     for (int i=0; i<n; i++)
           ta[1].s[i] = ta[2].s[i] = 0;
    //若n为偶数,按顺时针方向依次摆放 A B C
     if (n%2 == 0)
     {
           ta[1].name = 'B';
           ta[2].name = 'C';
     }
     else  //若n为奇数,按顺时针方向依次摆放 A C B
     {
           ta[1].name = 'C';
           ta[2].name = 'B';
     }
}
 
long Pow(int x, int y)
{
     long sum = 1;
     for (int i=0; i<y; i++)
           sum *= x;
     return sum;
}
 
void Hannuota(st ta[], long max)
{
  intk = 0; //累计移动的次数
  inti = 0;
  intch;
 while (k < max)
  {
   //按顺时针方向把圆盘1从现在的柱子移动到下一根柱子
   ch = ta[i%3].Pop();
  ta[(i+1)%3].Push(ch);
  cout << ++k << ": " <<
        "Move disk " << ch << " from " <<ta[i%3].name <<
        " to " << ta[(i+1)%3].name << endl;
  i++;
   //把另外两根柱子上可以移动的圆盘移动到新的柱子上
   if(k < max)
  {    
   //把非空柱子上的圆盘移动到空柱子上,当两根柱子都为空时,移动较小的圆盘
   if (ta[(i+1)%3].Top() == 0 ||
       ta[(i-1)%3].Top() > 0 &&
       ta[(i+1)%3].Top() > ta[(i-1)%3].Top())
   {
       ch =  ta[(i-1)%3].Pop();
       ta[(i+1)%3].Push(ch);
       cout << ++k << ": " << "Move disk"
            << ch << " from " << ta[(i-1)%3].name
            << " to " << ta[(i+1)%3].name << endl;
    }
   else
    {
      ch =  ta[(i+1)%3].Pop();
      ta[(i-1)%3].Push(ch);
      cout << ++k << ": " << "Move disk"
           << ch << " from " << ta[(i+1)%3].name
           << " to " << ta[(i-1)%3].name << endl;
    }
 }
}
}


3、 实验结果及分析(测试时以7阶汉诺塔为例)

使用递归算法时运行的情况:


使用非递归算法时运行的情况:


      从实验结果可以看出,与n皇后问题不同,对于汉诺塔问题的求解,当使用递归的方法来解决时它的时间复杂度比非递归的方法要好。而且,使用递归算法写代码时更容易理解。通过对于汉诺塔问题非递归与递归方法的对比可以得出结论:有的时候使用的递归的方法对于问题的求解不仅更能使人容易理解,而且效率更高。我们在以后编代码时也应该注意递归方法的使用。





经典递归算法—汉诺塔问题(含代码示例) 相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如图1)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。 阅读详情

相关推荐

递归经典例题 --- 汉诺塔(图文详解)

保姆级带你了解汉诺塔

Weraphael的博客 1万+

汉诺塔的图解递归算法

汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根...

Rnan_prince的博客 10万+

汉诺塔问题的非递归算法实现

在非递归算法设计中,栈(Stack)和队列(Queue)是最为常见的数据结构。栈是一种后进先出(LIFO, Last In First Out)的数据结构,只能在一端(称为栈顶)进行插入和删除操作。队列是一种先进先出(FIFO, First In First Out)的数据结构,支持在一端添加元素,而在另一端移除元素。对于栈而言,它适用于那些需要回溯或撤销操作的场景,例如表达式求值、浏览器的后退功能等。队列则非常适合处理按顺序排列或处理的任务,如任务调度、打印队列等。

weixin_42513928的博客 1175

汉诺塔问题(递归与非递归)

关于汉诺塔问题的过程分析以及递归非递归两种解法的推理

月巴虫丰博客 4492

ubuntu安装eigen3.3.7

查看已安装版本: gedit /usr/include/eigen3/Eigen/src/Core/util/Macros.h 或 gedit /usr/local/include/eigen3/Eigen/src/Core/util/Macros.h 卸载先前版本: sudo updatedb locate eigen3 得到eigen库的位置 卸载: sudo rm -rf /usr/include/eigen3 /usr/lib/cmake/eigen3 ...

reason的博客 1万+

SAP各模块表清单及逻辑关系介绍

分享韩国同行总结的各模块的表清单及逻辑关系,这对ABAP顾问和各模块业务顾问应该非常有用的 物料主数据 SD与MM PS模块 PP模块 QM模块 CO模块 FI模块

weixin_40672823的博客 9599

汉诺塔问题C语言非递归算法

汉诺塔(Hanoi)问题是学习递归算法时一个很经典的例子,通过递归算法解决,在C站上很多很多,今日就跟着鸡翅一起学习一下非递归算法吧!这次使用的是栈堆的数据结构。//先定义栈元素 int n;//n表示当前是第几个圆盘 char a , b , c;// a,b,c代表三个柱子,a为当前圆盘所在柱子, b为可以借助的柱子, c为目标柱子,即要放到的那个位置的柱子 bool flag;//代表此时圆盘可以移动不 } elem;int top;// top标记栈顶元素 elem e [ 64 ];

一个学习网安的鸡翅 3790

《iOS之一起进大厂》系列-秒杀面试官的RunLoop底层原理面试题

Runloop是iOS面试中的必考题,不管大厂小厂都会问到。 这里包括了Runloop几乎所有的面试题,还有中肯完整的答案解释。

空杯子 1151

c语言汉诺塔递归算法_汉诺塔问题的递归和非递归算法

(给算法爱好者加星标,修炼编程内功)来源:IT修道者https://blog.youkuaiyun.com/computerme/article/details/18080511汉诺塔问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不...

weixin_39926613的博客 1432

使用DeepSeek、MCP和AKShare实现智能金融问答系统技术方案

DeepSeek是由深度求索公司开发的大规模语言模型,最新版本DeepSeek-V3采用混合专家(MoE)架构,拥有671B参数,激活37B参数,在多项基准测试中表现优异3。要使用DeepSeek的API服务:访问DeepSeek平台注册账号获取API Key(形如AKShare是基于Python的金融数据接口库,提供股票、基金、期货、宏观经济等领域的海量数据。主要特点包括:免费开源,数据源丰富支持多种数据格式(DataFrame/JSON)持续更新维护安装命令。

Kin 3172

Linux平台CCS安装配置完整示例

手把手讲解在Linux系统中完成CCS安装与环境配置的全过程,涵盖关键步骤与常见问题解决,是查找ccs安装教程时不可多得的实战指南。

weixin_42601134的博客 514

汉诺塔问题的递归算法和非递归算法分析

汉诺塔问题的递归算法和非递归算法分析 第一次发博客,想要以此记录自己的学习过程,也方便以后查看复习。希望能坚持下去。 问题描述 相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置n个金盘(依次标号1到n)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,...

笨手笨脚°的博客 6844

浅析图像处理中的名词:Gamma 校正(Gamma变换、Gamma调整)

浅析图像处理中的名词:Gamma 校正(Gamma变换、Gamma调整)

qq_51908382的博客 1万+

利用问题归约法实现hanoi塔问题_有趣的汉诺塔问题的非递归算法

汉诺塔问题的递归程序很简单,也很容易理解,C源程序如下。// 程序1#include int n;void move(int k, char from, char to) { static int Ser_num; Ser_num++; printf("%3d k=%2d %c-->%c\n",Ser_num,k,from, to); return;}void han...

weixin_32338107的博客 1613

PICO SCOPE 二次开发

基于C#开发一个简单的PICO示波器的上位机工作,与MCC600运动控制卡一起,实现数据自动采集

nixoncheng的博客 1147

[Dify 实战] 如何在内网环境部署 Dify 应用:彻底离线的企业级方案解析

企业内网环境如何离线部署Dify?本文提供详细教程:Dify作为开源AI平台,支持完全离线部署,无需外网访问。文中介绍两种部署方式:推荐使用Docker一键部署,也可选择源码安装定制化方案。重点讲解内网模型配置(支持Ollama/GPT-OSS等)、知识库存储(MinIO/PostgreSQL)及内网代理设置,并给出常见问题排查方法。该方案适用于金融、政府等对数据安全要求高的场景,确保敏感数据不泄露,实现完全本地化的AI应用闭环。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 452

用非递归算法解决Hanoi汉诺塔问题

开天辟地的神勃拉玛(和中国的盘古差不多的神吧)在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。计算结果非常恐怖(移动圆片的次数)18446744073709551615,众僧们即便是耗尽毕生精力也不可能完成金

1767

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

非递归汉诺塔算法C语言,汉诺塔问题非递归算法-C

该楼层疑似违规已被系统折叠隐藏此楼查看此楼/*网上看到别人发的关于汉诺塔问题非递归算法,每次都看得有点晕,今天又看了一次,终于明白了其实现原理传统的递归方法效率极其低下,时间和空间复杂度均呈几何级数增长,当问题规模达到20时,计算时间很漫长,更不用谈30以后的了,所以,寻找一种非递归方法就很有必要了。下面是笔者刚刚完成的c++算法*/#include#includeusing namespace...

weixin_28711397的博客 794

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

汉诺塔问题的递归算法和非递归算法

我们定义f ( n ) f(n)f(n)是需要移动的次数;时间复杂度=2^n-1。

m0_62865498的博客 431

汉诺塔问题(递归和非递归算法)

#include<stdio.h> void hanoi(int n,char a,char b,char c) { if(n==1)printf("盘号:%d,%c-->%c\n",n,a,b); if(n==2) { printf("盘号:%d,%c-->%c\n",1,a,c); printf("盘号:%d,%c-->%c\n",2,a,b); printf("盘号:%d,%c-->%c\n",1,c,b); }//递归初始条件 if(n&gt

何以琛 558

有趣的汉诺塔问题的非递归算法

汉诺塔问题的递归程序很简单,也很容易理解,C源程序如下。 // 程序1 #include <stdio.h> int n; void move(int k, char from, char to) { static int Ser_num; Ser_num++; printf("%3d k=%2d %c-->%c\n",Ser_num,k,from, to); return; } void hanoi(int k,char from,char pass,char

lhwhit的专栏 421

P123 例6-6 借助堆栈模拟系统的运行时进栈、出栈过程,把汉诺塔问题的递归算法转换为非递归算法,并分析非递归算法的时间复杂度。

P123 例6-6 借助堆栈模拟系统的运行时进栈、出栈过程,把汉诺塔问题的递归算法转换为非递归算法,并分析非递归算法的时间复杂度。 头文件:SeqStack.h #include<stdio.h> #define MaxStackSize 100 typedef struct { int retAddr; int nPara; char fromPegPara; char toPegPara; char auxPegPara; }DataType; typedef struct

AKK188888881的博客 243

汉诺塔问题非递归算法集锦

汉诺塔问题博大精深,我稍微搜集整理了一下,就得到如此多方法,还有好些方法一时不能理解,没有贴出来,请广大网友共同探讨,分享更多更好的方法。

QiaoRuoZhuo的专栏 6656

数据结构:堆栈的应用(汉诺塔问题递归、非递归算法实现)

本文将通过完成以下内容来展示在数据结构中堆栈的应用(汉诺塔问题递归、非递归算法实现),代码解释标注全面而且清晰,代码书写也十分规范,适合初学者进行学习,本篇文章算是本人的一些学习记录分享,希望对有需要的小伙伴提供一些帮助~

m0_63464778的博客 1310

c语言汉诺塔递归算法转非递归,汉诺塔问题非递归算法-C

该楼层疑似违规已被系统折叠隐藏此楼查看此楼/*网上看到别人发的关于汉诺塔问题非递归算法,每次都看得有点晕,今天又看了一次,终于明白了其实现原理传统的递归方法效率极其低下,时间和空间复杂度均呈几何级数增长,当问题规模达到20时,计算时间很漫长,更不用谈30以后的了,所以,寻找一种非递归方法就很有必要了。下面是笔者刚刚完成的c++算法*/#include#includeusing namespace...

weixin_36243739的博客 228

汉诺塔算法的递归与非递归的C以及C++源代码

汉诺塔(又称河内塔)问题其实是印度的一个古老的传说。 开天辟地的神勃拉玛(和中国的盘古差不多的神吧)在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用

lniwn 2698
上一篇: n皇后问题的三种解法
下一篇: opencv中的meanshift图像分割
IT修道者
IT修道者 领域专家: 人工智能技术领域 领域专家: 人工智能技术领域
博客等级 码龄17年 326粉丝 95原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值