用栈模拟汉诺塔问题

Posted 573583868wuy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用栈模拟汉诺塔问题相关的知识,希望对你有一定的参考价值。

在经典的汉诺塔问题中,有 3 个塔和 N 个可用来堆砌成塔的不同大小的盘子。要求盘子必须按照从小到大的顺序从上往下堆 (如,任意一个盘子,其必须堆在比它大的盘子上面)。同时,你必须满足以下限制条件:

(1) 每次只能移动一个盘子。
(2) 每个盘子从堆的顶部被移动后,只能置放于下一个堆中。
(3) 每个盘子只能放在比它大的盘子上面。

请写一段程序,实现将第一个堆的盘子移动到最后一个堆中。

 

分析:

技术分享图片

(1)n == 1

             第1次  1号盘  A---->C       sum = 1 次

       (2)  n == 2

             第1次  1号盘  A---->B

             第2次  2号盘  A---->C

             第3次  1号盘  B---->C        sum = 3 次

  (3)n == 3

        第1次  1号盘  A---->C

        第2次  2号盘  A---->B

        第3次  1号盘  C---->B

        第4次  3号盘  A---->C

        第5次  1号盘  B---->A

        第6次  2号盘  B---->C

        第7次  1号盘  A---->C        sum = 7 次

设栈A上最初的盘子总数为n,

当n=1时,只要将编号为1的盘子从栈A直接移到栈C上即可;否则执行以下三步:

(1)用栈C做过渡,将栈A上的n-1个盘子移到栈B上;

(2)将栈A上的最后一个盘子直接移到栈C上面;

(3)用栈A做过渡,将栈B上面的n-1个盘子移到栈C上面;

根据这种解法,如何将n-1个盘子从一个栈移到另一个栈的问题是一个和原问题具有相同特征属性的问题,只是问题的规模-1,因此可以用相同的方法求解。

  1 <?php
  2 header("Content-type: text/html; charset=utf-8");
  3 class Stack
  4 {
  5     private $id = null;//栈的标识,用于区分从哪个栈移到哪个栈
  6     private $top = -1;//栈顶
  7     private $max_size = 100;//栈的最大容量
  8     private $stack = array();
  9     
 10     public function __construct($id)
 11     {
 12         $this->id = $id;
 13     }
 14     
 15     public function get_id()
 16     {
 17         return $this->id;
 18     }
 19     
 20     /**
 21      * 入栈
 22      */
 23     public function push($val)
 24     {
 25         if($this->top == $this->max_size-1)
 26         {
 27             return false;//栈满
 28         }
 29         $this->top++;
 30         $this->stack[$this->top] = $val;
 31     }
 32     
 33     /**
 34      * 出栈
 35      */
 36     public function pop()
 37     {
 38         if($this->top == -1)
 39         {
 40             return false;//栈空
 41         }
 42         $val = $this->stack[$this->top];
 43         unset($this->stack[$this->top]);
 44         $this->top--;
 45         return $val;
 46     }
 47 }
 48 
 49 /**
 50  * 将栈A上的n个盘子移动到栈C上面,栈B用作辅助
 51  */
 52 function hanoi($n, $stack_a, $stack_b, $stack_c)
 53 {
 54     if($n == 1)//只有一个盘子时,直接移动到目标栈
 55     {
 56         move($stack_a, $stack_c);
 57     } else {
 58         hanoi($n-1, $stack_a, $stack_c, $stack_b);//将栈A上编号为1至n-1个盘子移到栈B上,栈C作为辅助
 59         move($stack_a, $stack_c);//将编号为n的盘子从栈A移到C
 60         hanoi($n-1, $stack_b, $stack_a, $stack_c);//将栈B上编号为1至n-1个盘子移到栈C上,栈A作为辅助
 61     }
 62 }
 63 
 64 /**
 65  * 移动
 66  */
 67 function move($stack_a, $stack_c)
 68 {
 69     static $count = 0;//盘子移动的次数
 70     $val = $stack_a->pop();
 71     $stack_c->push($val);
 72     $count++;
 73     echo $count . ": 从栈" . $stack_a->get_id() . "把" . $val . "移到栈" . $stack_c->get_id() . "<br/>"; 
 74 }
 75 
 76 /**
 77  * 递归解法($n: 表示有多少个盘子)
 78  * 1.先创建3个栈,并初始化栈A
 79  * 2.将栈A上的n个盘子移动到栈C上面,栈B用作辅助
 80  * 3.打印盘子的移动轨迹
 81  */
 82 function solution($n = 3)
 83 {
 84     $A = new Stack(‘A‘);
 85     $B = new Stack(‘B‘);
 86     $C = new Stack(‘C‘);
 87     for($i=$n;$i>0;$i--)
 88     {
 89         $A->push($i);
 90     }
 91     
 92     hanoi($n, $A, $B, $C);
 93     
 94     //打印盘子的移动轨迹
 95     echo "<pre>";
 96     print_r($A);
 97     print_r($B);
 98     print_r($C);
 99     die;
100 }
101 
102 solution(4);

 



以上是关于用栈模拟汉诺塔问题的主要内容,如果未能解决你的问题,请参考以下文章

Java编程用栈来求解汉诺塔问题的代码实例(非递归)_java - JAVA

算法题06-用栈来解决汉诺塔问题

左神算法书籍《程序员代码面试指南》——1_06用栈来求解汉诺塔问题

用栈来求解汉诺塔问题

1.6 用栈来求解汉诺塔问题

Hanoi(汉诺塔问题)用栈来求解