【数据结构学习笔记】——用链表形式的栈完成汉诺塔

要求

使用链表形式的栈完成汉诺塔(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)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值