要求
使用链表形式的栈完成汉诺塔(8个碟子)移动任务。并且标出每一步移动的动作。
算法设计
汉诺塔问题利用递归的思想,仅有1个碟子时只需要将它移动一次。若有n个碟子时可以先将n-1个碟子移动到辅助塔上,再将最大的移动到目标塔上,此时可以忽略这个碟子(因为它最大而且不用再次移动)。再将n-1个碟子移动到目标塔上借助初始塔。
代码实现
自己编写的链表形势的栈 LinkedStack.h
#ifndef LINKEDSTACK_H
#define LINKEDSTACK_H
using namespace std;
//先声明一个模板类
template <class T> class LinkedStack;
//定义节点类
template <class T>
class Node{
friend LinkedStack<T>;
private:
T data;
Node<T>*link;
};
class NoMem
{
public:
NoMem() {}
};
//定义链表式栈
template<class T>
class LinkedStack{
public:
LinkedStack(){top=0;}
~LinkedStack();
bool isEmpty()const{return top==0;};
bool isFull()const;
T Top()const;
LinkedStack<T>&Add(const T&x);
LinkedStack<T>&Delete( T&x);
private:
Node<T>*top;
};
//析构函数,清空所有节点
template<class T>
LinkedStack<T>::~LinkedStack(){
Node<T>*next;
while(top){
next=top->link;
delete top;
top=next;
}
}
//判断是否满
template<class T>
bool LinkedStack<T>::isFull()const{
try{Node<T>*p=new Node<T>;
delete p;
return false;
}
catch(NoMem &nomem){return true;}
}
//返回栈顶元素
template<class T>
T LinkedStack<T>::Top()const{
if(isEmpty()) return;
return top->data;
}
//增加一个元素
template<class T>
LinkedStack<T>&LinkedStack<T>::Add(const T&x) //返回类型为LinkedStack<T>。因为是成员函数 所以需要::。使用& 作为引用返回 不会增加副本
{
Node<T>*p=new Node<T>;
p->data=x;
p->link=top; //p指向原来的栈顶元素
top=p; //将新增加的p,作为栈顶元素top
return*this;
}
//删除一个元素 把栈顶元素保存在x中
template<class T>
LinkedStack<T>&LinkedStack<T>::Delete( T&x){
if(isEmpty()) cout<<"error";
x=top->data;
Node<T>*p=top;
top=top->link; //指向栈顶下面的第一个元素
delete p; //“后事”交代完毕,删除原来的栈顶指针
return *this;
}
#endif
ChainHanoi.cpp
#include<iostream>
#include"LinkedStack.h"
using namespace std;
int sum=1; //全局变量,用于计步数
//汉诺塔类 包含 移动函数 和 3个塔 1 2 3
class Hanoi{
friend void TowersOfHanoi(int n);
public:
void TowersOfHanoi(int n,int x,int y,int z);
private:
LinkedStack<int>*S[4]; //为了编号 1 2 3 所以需要4个
};
//递归 n个盘子 从x到y 借助 z
void Hanoi::TowersOfHanoi(int n,int x,int y,int z){
int d;
if(n>0){
TowersOfHanoi(n-1,x,z,y); //先将n-1个碟子从x移到z借助y
S[x]->Delete(d); //将x中的最大的盘子移动到y上
S[y]->Add(d);
cout<<sum++<<": "<<x <<"--->"<<y <<" "<<endl; //在输出中显示出来
TowersOfHanoi(n-1,z,y,x); //再将n-1个碟子从z一定到y借助x (此时x中的最大的碟子已经移动到了y)
}
}
//将汉诺塔转化为链表栈的数据类型 n为碟子数目
void TowersOfHanoi(int n){
Hanoi X;
X.S[1]=new LinkedStack<int>;
X.S[2]=new LinkedStack<int>;
X.S[3]=new LinkedStack<int>;
for(int d=n;d>0;d--){ //将盘子(数据)放在塔(栈)上
X.S[1]->Add(d); //从大到小 将n个数据压入栈中
}
X.TowersOfHanoi(n,1,2,3); //将n个碟子 从塔1挪到塔2 借助塔3
}
int main(){
TowersOfHanoi(8); //调用函数前不用加类型!!!!
return 0;
}
如果是输出到文件 则修改代码段
#include<fstream>
void Hanoi::TowersOfHanoi(int n,int x,int y,int z){
int d;
if(n>0){
TowersOfHanoi(n-1,x,z,y); //先将n-1个碟子从x移到z借助y
S[x]->Delete(d); //将x中的最大的盘子移动到y上
S[y]->Add(d);
cout<<sum<<": "<<x <<"--->"<<y <<" "<<endl; //在输出中显示出来
ofstream outfile;
outfile.open("outfile.txt",ios::app); //ios::app 是在原文件上增加不覆盖之前的数据
outfile<<sum++<<": "<<x <<"--->"<<y <<" "<<endl;
outfile.close();
TowersOfHanoi(n-1,z,y,x); //再将n-1个碟子从z一定到y借助x (此时x中的最大的碟子已经移动到了y)
}
结果
1: 1—>3
2: 1—>2
3: 3—>2
4: 1—>3
5: 2—>1
6: 2—>3
7: 1—>3
8: 1—>2
9: 3—>2
10: 3—>1
11: 2—>1
12: 3—>2
13: 1—>3
14: 1—>2
15: 3—>2
16: 1—>3
17: 2—>1
18: 2—>3
19: 1—>3
20: 2—>1
21: 3—>2
22: 3—>1
23: 2—>1
24: 2—>3
25: 1—>3
26: 1—>2
27: 3—>2
28: 1—>3
29: 2—>1
30: 2—>3
31: 1—>3
32: 1—>2
33: 3—>2
34: 3—>1
35: 2—>1
36: 3—>2
37: 1—>3
38: 1—>2
39: 3—>2
40: 3—>1
41: 2—>1
42: 2—>3
43: 1—>3
44: 2—>1
45: 3—>2
46: 3—>1
47: 2—>1
48: 3—>2
49: 1—>3
50: 1—>2
51: 3—>2
52: 1—>3
53: 2—>1
54: 2—>3
55: 1—>3
56: 1—>2
57: 3—>2
58: 3—>1
59: 2—>1
60: 3—>2
61: 1—>3
62: 1—>2
63: 3—>2
64: 1—>3
65: 2—>1
66: 2—>3
67: 1—>3
68: 2—>1
69: 3—>2
70: 3—>1
71: 2—>1
72: 2—>3
73: 1—>3
74: 1—>2
75: 3—>2
76: 1—>3
77: 2—>1
78: 2—>3
79: 1—>3
80: 2—>1
81: 3—>2
82: 3—>1
83: 2—>1
84: 3—>2
85: 1—>3
86: 1—>2
87: 3—>2
88: 3—>1
89: 2—>1
90: 2—>3
91: 1—>3
92: 2—>1
93: 3—>2
94: 3—>1
95: 2—>1
96: 2—>3
97: 1—>3
98: 1—>2
99: 3—>2
100: 1—>3
101: 2—>1
102: 2—>3
103: 1—>3
104: 1—>2
105: 3—>2
106: 3—>1
107: 2—>1
108: 3—>2
109: 1—>3
110: 1—>2
111: 3—>2
112: 1—>3
113: 2—>1
114: 2—>3
115: 1—>3
116: 2—>1
117: 3—>2
118: 3—>1
119: 2—>1
120: 2—>3
121: 1—>3
122: 1—>2
123: 3—>2
124: 1—>3
125: 2—>1
126: 2—>3
127: 1—>3
128: 1—>2
129: 3—>2
130: 3—>1
131: 2—>1
132: 3—>2
133: 1—>3
134: 1—>2
135: 3—>2
136: 3—>1
137: 2—>1
138: 2—>3
139: 1—>3
140: 2—>1
141: 3—>2
142: 3—>1
143: 2—>1
144: 3—>2
145: 1—>3
146: 1—>2
147: 3—>2
148: 1—>3
149: 2—>1
150: 2—>3
151: 1—>3
152: 1—>2
153: 3—>2
154: 3—>1
155: 2—>1
156: 3—>2
157: 1—>3
158: 1—>2
159: 3—>2
160: 3—>1
161: 2—>1
162: 2—>3
163: 1—>3
164: 2—>1
165: 3—>2
166: 3—>1
167: 2—>1
168: 2—>3
169: 1—>3
170: 1—>2
171: 3—>2
172: 1—>3
173: 2—>1
174: 2—>3
175: 1—>3
176: 2—>1
177: 3—>2
178: 3—>1
179: 2—>1
180: 3—>2
181: 1—>3
182: 1—>2
183: 3—>2
184: 3—>1
185: 2—>1
186: 2—>3
187: 1—>3
188: 2—>1
189: 3—>2
190: 3—>1
191: 2—>1
192: 3—>2
193: 1—>3
194: 1—>2
195: 3—>2
196: 1—>3
197: 2—>1
198: 2—>3
199: 1—>3
200: 1—>2
201: 3—>2
202: 3—>1
203: 2—>1
204: 3—>2
205: 1—>3
206: 1—>2
207: 3—>2
208: 1—>3
209: 2—>1
210: 2—>3
211: 1—>3
212: 2—>1
213: 3—>2
214: 3—>1
215: 2—>1
216: 2—>3
217: 1—>3
218: 1—>2
219: 3—>2
220: 1—>3
221: 2—>1
222: 2—>3
223: 1—>3
224: 1—>2
225: 3—>2
226: 3—>1
227: 2—>1
228: 3—>2
229: 1—>3
230: 1—>2
231: 3—>2
232: 3—>1
233: 2—>1
234: 2—>3
235: 1—>3
236: 2—>1
237: 3—>2
238: 3—>1
239: 2—>1
240: 3—>2
241: 1—>3
242: 1—>2
243: 3—>2
244: 1—>3
245: 2—>1
246: 2—>3
247: 1—>3
248: 1—>2
249: 3—>2
250: 3—>1
251: 2—>1
252: 3—>2
253: 1—>3
254: 1—>2
255: 3—>2
可以看出来,8个碟子需要2^8-1 步。所以O(2^n)。