博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
汉诺塔
阅读量:5753 次
发布时间:2019-06-18

本文共 9304 字,大约阅读时间需要 31 分钟。

摘要:汉诺塔大家都知道怎么玩,就是n个圆盘从柱子A移到柱子C。在移动过程中,小盘一定要在大盘上面,所以用到起中转作用的柱子B。下面的代码中有三个解法,一个是递归的,另两个是非递归的。

稍微讲一下非递归的:

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

        首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子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)操作,最后就能按规定完成汉诺塔的移动。

方法二、通过二叉树

        先看图,借用了 文章 的图如下:

中序遍历这棵树就得到汉诺塔的操作过程:

1:one->three; => 2:one->two; => 1:three->two; => 3:one->three; =>1:two->one; => 2:two->three; => 1:one->three

View Code
1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5   6 namespace Hanoi  7 {  8     struct Disk  9     { 10         public const int MAX = 64; 11  12         int top; //栈顶,用来最上面的圆盘 13         char name; //柱子的名字,可以是A,B,C中的一个 14  15         int[] s; //柱子上的圆盘存储情况 16  17         public int[] S 18         { 19             get 20             { 21                 //初始化 22                 if (s == null) 23                     s = new int[MAX]; 24                 return s; 25             } 26             set 27             {                28                 s = value; 29             } 30         } 31  32         public int Top 33         { 34             get { return top; } 35             set { top = value; } 36         } 37  38         public char Name 39         { 40             get { return name; } 41             set { name = value; } 42         } 43  44         public bool IsEmpty() 45         { 46             return top == -1; 47         } 48         public int Peek()//取栈顶元素 49         {             50             return s[top]; 51         } 52         public int Pop()//出栈 53         { 54             return s[top--]; 55         } 56         public void Push(int x)//入栈 57         { 58             s[++top] = x; 59         } 60     } 61  62     class Node 63     { 64         int number; 65         char first; 66         char second; 67         char third; 68  69         public int Number 70         { 71             get { return number; } 72             set { number = value; } 73         } 74         internal char First 75         { 76             get { return first; } 77             set { first = value; } 78         } 79         internal char Second 80         { 81             get { return second; } 82             set { second = value; } 83         } 84         internal char Third 85         { 86             get { return third; } 87             set { third = value; } 88         } 89  90         public Node GetLeft() 91         { 92             if (number == 1) 93                 return null; 94             Node node = new Node(); 95             node.number=this.number-1; 96             node.first = this.first; 97             node.second = this.third; 98             node.third = this.second; 99             return node;100         }101         public Node GetRight()102         {103             if (number == 1)104                 return null;105             Node node = new Node();106             node.number = this.number - 1;107             node.first = this.second;108             node.second = this.first;109             node.third = this.third;110             return node;111         }112     }    113 114     class Program115     {116         static void Main(string[] args)117         {118             Console.WriteLine("递归实现");119             Hannoi(4, 'A', 'B', 'C');120 121             Console.WriteLine("非递归实现1");122             int n = 4;123             Disk[] ta = Creat(n); //给结构数组设置初值 124             long max = Pow(2, n) - 1;//移动的次数应等于2^n - 1125             Hannuota(ta, max);//移动汉诺塔的主要函数 126 127             Console.WriteLine("非递归实现2");128             Hanoi(4, 'A', 'B', 'C');129             Console.Read();130         }131 132         #region 递归实现133         static void Hannoi(int n, char a, char b, char c)134         {135             if (n == 1)136                 Move(1, a, c);137             else138             {139                 Hannoi(n - 1, a, c, b);140                 Move(n, a, c);141                 Hannoi(n - 1, b, a, c);142             }143         }144         static void Move(int n, char x, char y)145         {146             Console.WriteLine("Move disk {0} from {1} to {2}", n, x, y);147         }148         #endregion149 150         #region 非递归实现1151         static Disk[] Creat(int n)152         {153             Disk[] ta = new Disk[3];154             ta[0].Name = 'A';155             ta[0].Top = n - 1;156             //把所有的圆盘按从大到小的顺序放在柱子A上157             for (int i = 0; i < n; i++)158             {159                 ta[0].S[i] = n - i;160             }161             //柱子B,C上开始没有没有圆盘162             ta[1].Top = ta[2].Top = -1;163             for (int i = 0; i < n; i++)164                 ta[1].S[i] = ta[2].S[i] = 0;165             //若n为偶数,按顺时针方向依次摆放 A B C166             if (n % 2 == 0)167             {168                 ta[1].Name = 'B';169                 ta[2].Name = 'C';170             }171             else  //若n为奇数,按顺时针方向依次摆放 A C B172             {173                 ta[1].Name = 'C';174                 ta[2].Name = 'B';175             }176             return ta;177         }178 179         static long Pow(int x, int y)180         {181             long sum = 1;182             for (int i = 0; i < y; i++)183                 sum *= x;184 185             return sum;186         }187 188         /// 189         /// 算法介绍:首先容易证明,当盘子的个数为n时,移动的次数应等于2^n - 1。190         /// 一位美国学者发现一种出人意料的方法,只要轮流进行两步操作就可以了。191         /// 首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子A上。根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C;若n为奇数,按顺时针方向依次摆放 A C B。192         /// (1)按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A。193         /// (2)接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘。这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。194         /// (3)反复进行(1)(2)操作,最后就能按规定完成汉诺塔的移动。195         /// 196         /// 197         /// 198         static void Hannuota(Disk[] ta, long max)199         {200             Console.WriteLine("累计移动次数:{0}", max);201             int k = 0; //累计移动的次数202             int i = 0;203             int ch;204             while (k < max)205             {206                 //按顺时针方向把圆盘1从现在的柱子移动到下一根柱子207                 ch = ta[i % 3].Pop();208                 ta[(i + 1) % 3].Push(ch);209                 ++k;210                 Console.WriteLine("Move dish {0} from {1} to {2}", ch, ta[i % 3].Name, ta[(i + 1) % 3].Name);211 212                 i++;213                 //把另外两根柱子上可以移动的圆盘移动到新的柱子上214                 if (k < max)215                 {         //把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘216                     if (ta[(i + 1) % 3].IsEmpty() ||217                         !ta[(i - 1) % 3].IsEmpty() &&218                         ta[(i + 1) % 3].Peek() > ta[(i - 1) % 3].Peek())219                     {220                         ch = ta[(i - 1) % 3].Pop();221                         ta[(i + 1) % 3].Push(ch);222                         ++k;223                         Console.WriteLine("Move dish {0} from {1} to {2}", ch, ta[(i - 1) % 3].Name, ta[(i + 1) % 3].Name);224                     }225                     else226                     {227                         ch = ta[(i + 1) % 3].Pop();228                         ta[(i - 1) % 3].Push(ch);229                         ++k;230                         Console.WriteLine("Move dish {0} from {1} to {2}", ch, ta[(i + 1) % 3].Name, ta[(i - 1) % 3].Name);231                     }232                 }233             }234         }235         #endregion236 237         #region 非递归实现2238         static void Hanoi(int n,char a,char b,char c)239         {240             Stack
s = new Stack
();241 Node p=new Node();242 p.Number = n;243 p.First = a;244 p.Second = b;245 p.Third = c;246 int i = 0;247 while (p != null || s.Count != 0)248 {249 while (p != null)250 {251 s.Push(p);252 p = p.GetLeft();253 }254 if (s.Count != 0)255 {256 p = s.Pop();257 i++;258 Console.WriteLine("Move disk {0} from {1} to {2}", p.Number.ToString(), p.First.ToString(), p.Third.ToString());259 p = p.GetRight();260 }261 }262 Console.WriteLine("累计移动次数:{0}", i);263 }264 #endregion265 }266 }

 网上找到汉诺塔操作可视化界面  。

 

Java递归简单实现

//汉诺塔public class HanoiTest {    public static void hanoi(int n, char A,char B,char C)    {        //何时结束,n=1(最后一块)        if(n==1)        {            move(A,C);            return;        }        //把n-1个从A->B        hanoi(n-1,A,C,B);        //最后1个充A->C        move(A,C);        //把n-1个从B->C        hanoi(n-1,B,A,C);    }    public static void move(char point1,char point2)    {        System.out.println(String.format("%c -> %c",point1,point2));    }    public static void main(String[] args)    {        hanoi(3,'A','B','C');    }}
View Code

 

 

转载于:https://www.cnblogs.com/Ming8006/archive/2013/01/23/2872686.html

你可能感兴趣的文章
SAP HANA存储过程结果视图调用
查看>>
设计模式 ( 十八 ):State状态模式 -- 行为型
查看>>
OracleLinux安装说明
查看>>
nova分析(7)—— nova-scheduler
查看>>
Entity Framework 实体框架的形成之旅--Code First模式中使用 Fluent API 配置(6)
查看>>
OpenMediaVault 搭建git,ssh无法连接问题
查看>>
java多线程之:Java中的ReentrantLock和synchronized两种锁定机制的对比 (转载)
查看>>
【Web动画】SVG 实现复杂线条动画
查看>>
使用Wireshark捕捉USB通信数据
查看>>
Apache Storm 官方文档 —— FAQ
查看>>
iOS 高性能异构滚动视图构建方案 —— LazyScrollView
查看>>
Java 重载、重写、构造函数详解
查看>>
【Best Practice】基于阿里云数加·StreamCompute快速构建网站日志实时分析大屏
查看>>
【云栖大会】探索商业升级之路
查看>>
HybridDB实例新购指南
查看>>
C语言及程序设计提高例程-35 使用指针操作二维数组
查看>>
华大基因BGI Online的云计算实践
查看>>
排序高级之交换排序_冒泡排序
查看>>
Cocos2d-x3.2 Ease加速度
查看>>
[EntLib]关于SR.Strings的使用办法[加了下载地址]
查看>>