• 汉诺塔 明


    摘要:汉诺塔大家都知道怎么玩,就是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 Program
    115     {
    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 - 1
    125             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             else
    138             {
    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         #endregion
    149 
    150         #region 非递归实现1
    151         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 C
    166             if (n % 2 == 0)
    167             {
    168                 ta[1].Name = 'B';
    169                 ta[2].Name = 'C';
    170             }
    171             else  //若n为奇数,按顺时针方向依次摆放 A C B
    172             {
    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         /// <summary>
    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         /// </summary>
    196         /// <param name="ta"></param>
    197         /// <param name="max"></param>
    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                     else
    226                     {
    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         #endregion
    236 
    237         #region 非递归实现2
    238         static void Hanoi(int n,char a,char b,char c)
    239         {
    240             Stack<Node> s = new Stack<Node>();
    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         #endregion
    265     }
    266 }

     网上找到汉诺塔操作可视化界面 http://figue.zdbit.com/cxzp.asp 。

    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
  • 相关阅读:
    cd /etc/init.d查看centos下自己注册的服务
    添加提前闭合标签 之后添加js可以执行js
    networkinterface 获取本机ip
    docker学习遇到的问题
    乌班图安装
    c3p0连接错误 An attempt by a client to checkout a Connection has timed out.
    【Spring开发】—— Spring注入静态变量
    mysql命令行导入导出
    IE8下不支持console.log()
    菜鸟教程
  • 原文地址:https://www.cnblogs.com/Ming8006/p/2872686.html
Copyright © 2020-2023  润新知