Xiangism

从一个无知角落里开始,蹒跚学步,一个未知到另一个未知,在跌跌撞撞中越走越快,越走越远,最后宇宙也为之开源。对于探索者来说,最后他们的思想总是变得和自己的足迹一样伟大。
随笔 - 62, 文章 - 1, 评论 - 220, 阅读 - 20万
  博客园  :: 首页  :: 联系 :: 管理
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

非递归汉斯塔

Posted on   Xiangism  阅读(1603)  评论(6编辑  收藏  举报

最近在看了大学算法的教程后,深深地理解到了递归算法在某些情况下的局限性,于是就想到了两年前自己做的汉斯塔的项目中的递归算法。能否将其变成循环算法呢?

 

为了简化,我是在VC++的控制台下来完成这个算法。

为了让程序更加清晰,定义了两个类Peg(柱子类),Disk(盘子类),当然内容就简化多了。类图如下:

  

Peg表示柱子类

Disks:vector<int>表示这个柱子上的所有盘子

Name:int表示柱子的名称。我将柱子将0,1,2进行了编号。以便接下来的运算

Disk表示盘子类

       Now:int   表示这个盘子现在所在的柱子

       WantTo:int      表示这个盘子将要移到哪个柱子上去

 

CLoopMove里就是有关用循环移盘子的算法

       对外的唯一接口就是LoopMove(int n):void ,参数n表示有几个盘子。

      

下面详细说明这个函数的实现过程:

1.先申明三个柱子对象

       Peg p0(0);      //起始柱

       Peg p1(1);      //目标柱

       Peg p2(2);      //辅助柱

然后将所以的盘子放在p1上

       为了操作方便,将这个三个变量放在数组中

Peg pegs[3]={p0,p1,p2};

 

2.接下来定义所有的盘子,并且现在盘子都在柱子0上。

       vector<Disk> disks;

       for (int i=0; i<n; ++i)

       {

              disks.push_back(Disk(0));

       }

 

3.由于用数学归纳法,很容易得出移动n个盘子的步数是2n-1,所以只需要循环这么多次就完成任务(如果不计算次数,也可以用死循环,并且在循环内判断游戏是否结束)。在每次循环中,       都调用FindMove()方法,来更新每个盘子的WantTo属性。具体的做法是:

       1.最大的盘子,也就是第n-1个盘子的目标肯定是p1

       2.循环从n-2个盘子到第0个盘子

              在循环中判断,比每个盘子大一的盘子是否已移到位。

              如果没有到位,则它应该移到“第三者”上去

                     disks[i].WantTo = 3 - disks[i+1].Now - disks[i+1].WantTo;  //这句代码最经典

                     比如,n-1号盘现在在0号柱上,要移到1号柱子上,那么n-2号柱子则应在2号柱上

              如果已到位,则这个盘子也应在这个柱子上

                     disks[i].WantTo = disks[i+1].WantTo;

 

4.将FindMove调用完后,就只需要从最小的盘子开始访问,看哪个需要移动,就移动之。

 

上面就是所有的程序结构,可以看出还有很大的优化空间,不用每次都去调用FindMove判断。

并且我现在的这个FindMove算法可以支持半自动。也就是不一定非要从所有的盘在p0上这个状态开始,可以从任何状态开始(当然小盘必须在大盘上面)。

 

在项目中,用递归的汉斯塔来进行比较,发现这个循环版本没有错误。代码下载:《非递归汉斯塔

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示