汉诺塔问题详解

6 篇文章 1 订阅
4 篇文章 0 订阅

汉诺塔问题


面试官:知道汉诺塔问题吗

菜鸡(我):知道,很简单,本质思想是递归

面试官:嗯…那写一下算法吧

菜鸡(我):…(咋写来着)

面试官:…(不会吧这都不知道)


背景

来源于百度百科

相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如图1)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
在这里插入图片描述


约定

  • 汉诺塔的三个柱子我分别定义为beginTower(A杆)auxiliaryTower(B杆)targetTower(C杆)

  • 通过游戏规则不难发现,汉诺塔的杆子上的金盘只有上一层的被取出,才能取下一层,这符合先入后出的规则,因此使用 表示汉诺塔的一根柱子

  • 使用 中的一个元素表示金盘,金盘的数值对应于元素的大小,金盘越大,元素的数值越大。


分析

只有一个元素(1)的情况
在这里插入图片描述

直接将元素1从beginTower中弹出,并压入到targetTower中

两个元素(1,2)的情况

  1. 将元素1从beginTower中弹出,并压入到auxiliaryTower中
  2. 将元素2从beginTower中弹出,并压入到targetTower中
  3. 将元素1从auxiliaryTower中弹出,并压入到targetTower中

三个元素(1,2,3)的情况
(长图警告)

  1. 将元素1从beginTower中弹出,并压入到targetTower中
  2. 将元素2从beginTower中弹出,并压入到auxiliaryTower中
  3. 将元素1从targetTower中弹出,并压入到auxiliaryTower中
  4. 将元素3从beginTower中弹出,并压入到targetTower中
  5. 将元素1从auxiliaryTower中弹出,并压入到beginTower中
  6. 将元素2从auxiliaryTower中弹出,并压入到targetTower中
  7. 将元素1从beginTower中弹出,并压入到targetTower中

规律

  1. beginTower中只有一个元素时,直接将该元素放入targetTower中
  2. beginTower有n个元素时:
    • 将beginTower中的n-1个元素放入auxiliaryTower,然后将beginTower最底层元素放入targetTower
    • 将auxiliaryTower中的n-2个元素放入beginTower,然后将auxiliaryTower最底层的元素放入targetTower
    • 再将beginTower中的n-3个元素放入auxiliaryTower,然后将beginTower最底层元素放入targetTower
    • …以此类推

算法

按照上面的规律,可以写出以下伪代码:

Hanoi(n, beginTower, auxiliaryTower, targetTower){

① if(n>1)Hanoi(n, beginTower, auxiliaryTower, targetTower)//如果金盘数量大于一,将前n-1个金盘移动到auxiliaryTower上
② move_to(beginTower,targetTower)//将beginTower中的最底层的金盘移动到targetTower中
③ if(n>1)Hanoi(n, beginTower, auxiliaryTower, targetTower)//如果金盘数量大于一,将前n-1个金盘从auxiliaryTower移动到targetTower上

}


实现

#include <stack>
#include <iostream>
using namespace std;

void HanoiTower(int n,stack<int>& beginTower, stack<int>& auxiliaryTower, stack<int>& targetTower) {
	//将前n-1层移动到auxiliaryTower上
	if (n> 1)HanoiTower(n - 1, beginTower, targetTower, auxiliaryTower);
	//将第n层移到targetTower上
	targetTower.push(beginTower.top());
	beginTower.pop();
	//将前n-1层从auxiliaryTower移动到targetTower上
	if (n> 1)HanoiTower(n - 1, auxiliaryTower, beginTower, targetTower);
}

int main() { 
	stack<int> beginTower;
	stack<int> auxiliaryTower;
	stack<int> targetTower;
	for (int i = 10; i > 0; --i) {
		beginTower.push(i);
	}
	HanoiTower(10,beginTower, auxiliaryTower, targetTower);
	while (!targetTower.empty()) {
		cout << targetTower.top() << endl;
		targetTower.pop();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值