• 堆栈应用(二):汉诺塔


    1、问题描述

      汉诺塔( Towers of Hanoi)问题来自一个古老的传说:在世界刚被创建的时候有一座钻石宝塔(塔1 ),其上有6 4个金碟(如图 5 - 4所示)。所有碟子按从大到小的次序从塔底堆放至塔顶。紧挨着这座塔有另外两个钻石宝塔(塔 2和塔3)。从世界创始之日起,婆罗门的牧师们就一直在试图把塔 1 上的碟子移动到塔 2上去,其间借助于塔 3的帮助。由于碟子非常重,因此,每次只能移动一个碟子。另外,任何时候都不能把一个碟子放在比它小的碟子上面。按照这个传说,当牧师们完成他们的任务之后,世界末日也就到了。在汉诺塔问题中,已知 n个碟子和 3 座塔。初始时所有的碟子按从大到小次序从塔 1 的底部堆放至顶部,我们需要把碟子都移动到塔 2,每次移动一个碟子,而且任何时候都不能把大碟子放到小碟子的上面。在继续往下阅读之前,可以先尝试对 n= 2 , 3和4来解决这个问题。
       一个非常优雅的解决办法是使用递归。为了把最大的碟子移动到塔 2,必须把其余n- 1 个碟子移动到塔 3,然后把最大的碟子移动到塔 2。接下来是把塔 3上的 n- 1 个碟子移动到塔 2,为此可以利用塔 2和塔1 。可以完全忽视塔 2上已经有一个碟子的事实,因为这个碟子比塔 3上将要移过来的任一个碟子都大,因此,可以在它上面堆放任何碟子。事实上递归本身就是用堆栈实现的。

      

    盘子移动次数为:

    推导可得moves(n)=2n-1,可以证明这实际上是最少移动次数

      假定希望给出每次移动之后三座塔的状态(即塔上的碟子及其次序),那么必须在内存中保留塔的状态,并在每次移动碟子之后,对塔的状态进行修改。这样每移动一个碟子时,就可以在一个输出设备(如计算机屏幕、打印机等)上输出塔的信息。由于从每个塔上移走碟子时是按照 L I F O的方式进行的,因此可以把每个塔表示成一个堆栈。三座塔在任何时候都总共拥有 个碟子,因此,如果使用链表形式的堆栈,只需申请 n个元素所需要的空间。如果使用的是基于公式化描述的堆栈,塔 1和塔2的容量都必须是 n,而塔3的容量必须为 n- 1 ,因而所需要的空间总数为 3n- 1 。前面的分析已经指出,汉诺塔问题的复杂性是以 为指数的函数,因此在可以接受的时间范围内,只能解决 值比较小(如 n≤ 3 0)的汉诺塔问题。对于这些较小的 值,基于公式描述和基于链表描述的堆栈在空间需求上的差别相当小,因此可以随意使用。
      本文使用基于链表描述的堆栈实现。

    2、代码实现

    汉诺塔程序(其中LinkedStack.h实现见堆栈的链表方式实现):

     1 #ifndef HANOICLASS_H
     2 #define HANOICLASS_H
     3 #include <iostream>
     4 #include "LinkedStack.h"
     5 
     6 using std::cout;
     7 using std::endl;
     8 
     9 class Hanoiclass
    10 {
    11     friend void TowersOfHanoi(int);
    12 public:
    13     void TowersOfHanoi(int n, int x, int y, int z);//递归解决汉诺塔
    14 private:
    15     LinkedStack<int> *S[4];
    16     void ShowState();//输出3个塔的状态
    17 };
    18 
    19 void Hanoiclass::TowersOfHanoi(int n, int x, int y, int z)
    20 {
    21     if (n > 0)
    22     {
    23         TowersOfHanoi(n - 1, x, z, y);
    24         cout << "Move top disk from tower " << x << "to top of tower " << y << std::endl;
    25         int temp;
    26         S[x]->Delete(temp);//从x塔顶移出盘子
    27         S[y]->Add(temp);//盘子移入y塔顶
    28         ShowState();
    29         TowersOfHanoi(n - 1, z, y, x);
    30     }
    31 }
    32 
    33 void TowersOfHanoi(int n)
    34 {
    35     Hanoiclass X;
    36     for (int i = 1; i < 4;++i)
    37     {
    38         X.S[i] = new LinkedStack<int>;
    39     }
    40 
    41     for (int d = n; d>0;--d)
    42     {
    43         X.S[1]->Add(d);
    44     }
    45     X.ShowState();
    46     X.TowersOfHanoi(n, 1, 2, 3);
    47     
    48 }
    49 
    50 void Hanoiclass::ShowState()
    51 {
    52     for (int i = 1; i < 4;++i)
    53     {
    54         cout << ""<<i<<": ";
    55         if (!S[i]->IsEmpty())
    56         {
    57             cout << *S[i];
    58         }
    59         cout << endl;
    60     }
    61     
    62 }
    63 #endif

    运行:

     1 // Hanoi.cpp : 定义控制台应用程序的入口点。
     2 //
     3 
     4 #include "stdafx.h"
     5 #include<iostream>
     6 #include "Hanoiclass.h"
     7 using std::cout;
     8 using std::cin;
     9 
    10 int _tmain(int argc, _TCHAR* argv[])
    11 {
    12     TowersOfHanoi(3);
    13     system("pause");
    14     return 0;
    15 }

    输出:

  • 相关阅读:
    CaseStudy(showcase)布局篇列表的排放与遮罩
    CaseStudy(showcase)布局篇全屏效果
    Css 学习
    JavaScript 学习之 修改对象创建新方法
    等额本息java实现
    纠结了一天的JAVA简单客户端服务器Socket编程终于解决了
    rhostudio备忘
    sql server学习
    enumeration学习
    cookie和session
  • 原文地址:https://www.cnblogs.com/haoliuhust/p/4260830.html
Copyright © 2020-2023  润新知