问题分析
汉诺塔问题是典型的递归问题,
- 假设有n个盘要移动,n>0;A、B、C分别为三个柱子,A是原始柱子(有盘),B是间接柱子,C是目标柱子
- 将n个盘从A移动到C,最终结果一定是,将n-1个盘移动到B,然后第n个盘移动到C
- 此时,A上没有盘,B上有n-1个盘,C上有一个盘n
- 有3可知,此时要做的是将B上的n-1个盘移动到C上,A是间接柱子
- 此时问题的状态回到第一步的,只是原始柱子从A变成了B,
- 重复到n==0即没有盘在A、B柱子上,算法结束。
实现
// # 3. n > 3的情况:
// 3.1 A作为起始点,将最底部的n号盘移动到C前需要将前面的n-1个盘子移动到间点B,移动完毕后,n-1个盘子在B上,最大得盘在C上,
// 3.2 因此,目前状态是B是起点,A是间接点,将最底部的n-1号盘移动到C上,需要将前面的n-2个盘子移动到间接点A上,
// 3.3 目前状态是A是起点,B是间接点,盘子个数是n-2个,状态回到3.1步骤,重复3.1步骤,直到剩下一个直接放到C,算法结束
#include<iostream>
using namespace std;
struct Node
{
int data;
char flag;
Node *next; //在队列中的下标
};
class Hnoi {
private:
Node *A;
Node *B;
Node *C;
int n;
int num;
public:
Hnoi(int n);
// start起点柱子,middle过度柱子(间接柱子),dest(目标柱子),n(最大盘号)
void move(Node* start, Node* middle, Node* dest, int n);
void start();
};
Hnoi::Hnoi(int n) {
this->n = n;
// 定义A、B、C三个栈结构
this->A = new Node;
this->A->data = 0;
this->A->flag = 'A';
this->B = new Node;
this->B->data = 0;
this->B->flag = 'B';
this->C = new Node;
this->C->data = 0;
this->C->flag = 'C';
}
// 移动函数(核心)
// start起点柱子,middle过度柱子(间接柱子),dest(目标柱子),n(最大盘号)
void Hnoi::move(Node* start, Node* middle, Node* dest, int n) {
if (n > 0) {
// 将n-1个移动到midlle间接柱子
this->move(start, dest, middle, n-1);
this->num++;
// 将n移动到dest目标柱子,输出移动结果
cout<<this->num<<"从"<<start->flag<<"移动到"<<dest->flag<<endl;
// 然后,状态变为n-1个盘子在middle柱子上,start柱子是空,因此,以middle为起点,start为间接点,将n-1号盘搬到dest上
this->move(middle, start, dest, n-1);
}
}
void Hnoi::start() {
this->num = 0;
this->move(this->A, this->B, this->C, this->n);
}
int main() {
int n = 1;
Hnoi hnoi(3);
hnoi.start();
return 0;
}
总结
个人总结:递归分析的解法主要是如何去划分解法相同的子问题,不要去思考实际,而是要用一个概括的方式去想象,更容易得出解。