顺序栈——双栈(Dual Stack)
1. 双栈的概念
1.1 双栈的定义
- 双栈是指两个顺序栈,是一种特殊的顺序栈。
1.2 双栈中各元素的逻辑及存储关系
- 双栈共享一个地址连续的存储单元。即程序同时需要两个栈时,可以定义一个足够的栈空间,该空间的两端分别设为两个栈的栈底,用bottom[0]=-1和bottom[1]=maxSize指示。
- 压入数据时,让两个栈的栈顶top[0]和top[1]都向中间伸展,如果指示栈顶的指针top[0]+1等于另一个栈顶的指针top[1]时两栈已满。
- 每次进栈时top[0]加1,top[1]减1,而退栈时top[0]减1,top[1]加1。
- 如果top[0] == -1且top[1] == maxSize两栈为空。
- 双栈示意图:
- 在双栈的情形下:
(1)各栈的初始化语句:bottom[0]=top[0]=-1,bottom[1]=top[1]=maxSize。
(2)栈满的条件为top[0]+1 == top[1]。
(3)栈空的条件为bottom[0]==top[0]==-1且bottom[1]==top[1]==maxSize。
2. 双栈的实现
2.1 双栈的类定义及其操作的实现
- 文件:SeqStack.h
#ifndef DUAL_STACK_H_ #define DUAL_STACK_H_ #include <iostream> #include <string> #include <strstream> using namespace std; const int defaultSize = 50; //默认栈空间大小 const int stackIncreament = 20; //栈溢出时扩展空间的增量 const int n = 2; //设置n=2个栈共有一个栈空间 template <class T> class DualStack { public: DualStack(int sz = defaultSize); //构造函数 ~DualStack(); //析构函数 public: bool Push(const T& x, int d) ; //新元素x进栈 bool Pop(T& x, int d); //栈顶元素出栈,并将该元素的值保存至x bool getTop(T& x, int d) const; //读取栈顶元素,并将该元素的值保存至x bool IsEmpty() const; //判断栈是否为空 bool IsFull() const; //判断栈是否为满 int getSize() const; //计算栈中元素个数 void MakeEmpty(); //清空栈的内容 public: template <class T> friend ostream& operator<<(ostream& os, const DualStack<T>& s); //输出栈中元素的重载操作<< private: T *Vector; //存放栈中元素的栈数组 int top[n]; //栈顶指针 int maxSize; //栈最大可容纳元素个数 }; //构造函数 template <class T> DualStack<T>::DualStack(int sz) { cout << "$ 执行构造函数" << endl; if (sz >= 0) { maxSize = sz; top[0] = -1; top[1] = maxSize; Vector = new T[maxSize]; } } //析构函数 template <class T> DualStack<T>::~DualStack() { cout << "$ 执行析构函数" << endl; delete[] Vector; Vector = NULL; } //新元素x进栈 template <class T> bool DualStack<T>::Push(const T& x, int d) { if (true == IsFull()) { return false; } if (0 == d) { top[0]++; } else { top[1]--; } Vector[top[d]] = x; return true; } //栈顶元素出栈,并将该元素的值保存至x template <class T> bool DualStack<T>::Pop(T& x, int d) { if (true == IsEmpty()) { return false; } x = Vector[top[d]]; if (0 == d) { top[0]--; } else { top[1]++; } return true; } //读取栈顶元素,并将该元素的值保存至x template <class T> bool DualStack<T>::getTop(T& x, int d) const { if (true == IsEmpty()) { return false; } x = Vector[top[d]]; return true; } //判断栈是否为空 template <class T> bool DualStack<T>::IsEmpty() const { return ((-1 == top[0]) && (maxSize == top[1])) ? true : false; } //判断栈是否为满 template <class T> bool DualStack<T>::IsFull() const { return (top[0] + 1 == top[1]) ? true : false; } //计算栈中元素个数 template <class T> int DualStack<T>::getSize() const { return (top[0] + 1) + (maxSize - top[1]); } //清空栈的内容 template <class T> void DualStack<T>::MakeEmpty() { delete[] Vector; top[0] = -1; top[1] = maxSize; Vector = new T[maxSize]; } //输出栈中元素的重载操作<< template <class T> ostream& operator<<(ostream& os, const DualStack<T>& s) { os << "top[0]=" << s.top[0] << endl; //输出栈1顶位置 for (int i = 0; i <= s.top[0]; i++) { os << "[" << i << "]" << " : " << s.Vector[i] << endl; } os << "top[1]=" << s.top[1] << endl; //输出栈2顶位置 for (int i = s.maxSize - 1; i >= s.top[1]; i--) { os << "[" << i << "]" << " : " << s.Vector[i] << endl; } return os; } #endif /* DUAL_STACK_H_ */
2.2 主函数(main函数)的实现
- 文件:main.cpp
#include "DualStack.h" #define EXIT 0 //退出 #define PUSH 1 //新元素x进栈 #define POP 2 //栈顶元素出栈,并将该元素的值保存至x #define GETTOP 3 //读取栈顶元素,并将该元素的值保存至x #define ISEMPTY 4 //判断栈是否为空 #define ISFULL 5 //判断栈是否为满 #define GETSIZE 6 //计算栈中元素个数 #define MAKEEMPTY 7 //清空栈的内容 #define OPERATOR_OSTREAM 8 //输出栈中元素的重载操作<< void print_description() { cout << "------------------------------>双栈<------------------------------" << endl; cout << "功能选项说明:" << endl; cout << "#0: 退出" << endl; cout << "#1: 新元素x进栈" << endl; cout << "#2: 栈顶元素出栈,并将该元素的值保存至x" << endl; cout << "#3: 读取栈顶元素,并将该元素的值保存至x" << endl; cout << "#4: 判断栈是否为空" << endl; cout << "#5: 判断栈是否为满" << endl; cout << "#6: 计算栈中元素个数" << endl; cout << "#7: 清空栈的内容" << endl; cout << "#8: 输出栈中元素的重载操作<<" << endl; cout << "--------------------------------------------------------------------" << endl; } //判断输入的字符串每个字符是否都是数值0~9 bool IsStackNumber(const string& s_num) { if (s_num.size() > 1) { return false; } if ((s_num[0] != ‘0‘) && (s_num[0] != ‘1‘)) { return false; } return true; } //判断输入的字符串每个字符是否都是数值0~9 bool IsNumber(const string& s_num) { for (size_t i = 0; i < s_num.size(); i++) { if ((s_num[i] < ‘0‘) || (s_num[i] > ‘9‘)) { return false; } } return true; } //类型转换——将string型转为模板类型T template <class T> T StrToTtype(const string& s_num) { T n_num; strstream ss_num; ss_num << s_num; ss_num >> n_num; return n_num; } //输入栈编号 template <class T> int get_item() { cout << "> 请输入栈编号,item = "; string s_item; cin >> s_item; while (false == IsStackNumber(s_item)) { cout << "* 输入有误,请重新输入:"; cin >> s_item; } return atoi(s_item.c_str()); } //输入数据值 template <class T> T get_data() { cout << "> 请输入数据值,data = "; string s_data; cin >> s_data; return StrToTtype<T>(s_data); } //输入数组的最大长度 template <class T> int get_maxsize() { cout << "> 请输入数组的最大长度,maxsize = "; string s_maxsize; cin >> s_maxsize; while (false == IsNumber(s_maxsize)) { cout << "* 输入有误,请重新输入:"; cin >> s_maxsize; } return atoi(s_maxsize.c_str()); } //构造双栈 template <class T> DualStack<T>* construct_dualstack() { cout << "\n==> 创建双栈" << endl; int n_maxsize = get_maxsize<T>(); DualStack<T> *dualStack = new DualStack<T>(n_maxsize); return dualStack; } //析构双栈 template <class T> void destory_seqstack(DualStack<T>* dualStack) { cout << "\n==> 释放双栈在堆中申请的空间,并将指向该空间的指针变量置为空" << endl; delete dualStack; dualStack = NULL; } //新元素x进栈 template <class T> void push(DualStack<T>* dualStack) { cout << "$ 执行新元素x进栈函数" << endl; T data = get_data<T>(); int d = get_item<T>(); if (false == dualStack->Push(data, d)) { cout << "* 进栈失败" << endl; return; } cout << "* 进栈成功,data = " << data << endl; } //栈顶元素出栈,并将该元素的值保存至x template <class T> void pop(DualStack<T>* dualStack) { cout << "$ 执行栈顶元素出栈并将该元素的值保存至x函数" << endl; T data; int d = get_item<T>(); if (false == dualStack->Pop(data, d)) { cout << "* 出栈失败" << endl; return; } cout << "* 出栈成功,data = " << data << endl; } //读取栈顶元素,并将该元素的值保存至x template <class T> void gettop(DualStack<T>* dualStack) { cout << "$ 执行读取栈顶元素并将该元素的值保存至x函数" << endl; T data; int d = get_item<T>(); if (false == dualStack->getTop(data, d)) { cout << "* 读取栈顶元素失败" << endl; return; } cout << "* 读取栈顶元素成功,data = " << data << endl; } //判断栈是否为空 template <class T> void isempty(DualStack<T>* dualStack) { cout << "$ 执行判断栈是否为空函数,IsEmpty = " << dualStack->IsEmpty() << endl; } //判断栈是否为满 template <class T> void isfull(DualStack<T>* dualStack) { cout << "$ 执行判断栈是否为满函数,IsFull = " << dualStack->IsFull() << endl; } //计算栈中元素个数 template <class T> void getsize(DualStack<T>* dualStack) { cout << "$ 执行计算栈中元素个数函数,Size = " << dualStack->getSize() << endl; } //清空栈的内容 template <class T> void makeempty(DualStack<T>* dualStack) { cout << "$ 执行清空栈的内容函数" << endl; dualStack->MakeEmpty(); } //输出栈中元素的重载操作<< template <class T> void operator_ostream(DualStack<T>* dualStack) { cout << "$ 执行输出栈中元素的重载操作<<函数" << endl; cout << *dualStack;//或operator<<(cout, *dualStack); } //双栈操作选择 template <class T> void select_operation(DualStack<T>* dualStack) { if (NULL == dualStack) { cout << "* 没有构造双栈,请先构造双栈。" << endl; return; } string s_operation; while (s_operation != "0") { cout << "\n==> 请输入功能选项编号(按\"0\"退出程序):"; cin >> s_operation; while (false == IsNumber(s_operation)) { cout << "* 输入有误,请重新输入:"; cin >> s_operation; } int n_operation = atoi(s_operation.c_str()); switch (n_operation) { case EXIT://退出 { cout << "$ 退出程序" << endl; break; } case PUSH://新元素x进栈 { push(dualStack); break; } case POP://栈顶元素出栈,并将该元素的值保存至x { pop(dualStack); break; } case GETTOP://读取栈顶元素,并将该元素的值保存至x { gettop(dualStack); break; } case ISEMPTY://判断栈是否为空 { isempty(dualStack); break; } case ISFULL://判断栈是否为满 { isfull(dualStack); break; } case GETSIZE://计算栈中元素个数 { getsize(dualStack); break; } case MAKEEMPTY://清空栈的内容 { makeempty(dualStack); break; } case OPERATOR_OSTREAM://输出栈中元素的重载操作<< { operator_ostream(dualStack); break; } default: { cout << "* 请输入正确的功能选项编号" << endl; break; } } } } int main(int argc, char* argv[]) { print_description(); DualStack<int> *dualStack = construct_dualstack<int>(); select_operation(dualStack); destory_seqstack(dualStack); system("pause"); return 0; }
3. 双栈的优缺点
3.1 优点
- 两栈的大小不是固定不变的,在实际运算过程中,一个栈有可能进栈元素多而体积大些,另一个则可能小些。
- 两个栈共用一个栈空间,相互调剂,灵活性强。
3.2 缺点
- 运算较为复杂。
- 长度为定值,中途不易扩充。
- 注:n(n>2)个栈的情况更有所不同,采用多个栈共享栈空间的顺序存储表示方式,处理十分复杂,在插入时元素的移动量很大,因而时间代价较高。特别是当整个存储空间即将充满时,这个问题更加严重。
- 解决上述问题的办法就是采用链接方式作为栈的存储表示方式。
3.3 双栈的适用情况
- 当栈满时要发生溢出,为了避免这种情况,需要为栈设立一个足够大的空间。但如果空间设置得过大,而栈中实际只有几个元素,也是一种空间浪费。此外,程序中往往同时存在几个栈,因为各个栈所需的空间在运行中是动态变化着的。如果给几个栈分配同样大小的空间,可能实际运行时,有的栈膨胀得快,很快就产生了溢出,而其他的栈可能此时还有许多空闲空间。这时就可以利用双栈,两个栈共用一个栈空间,相互调剂,灵活性强。
参考文献:
[1]《数据结构(用面向对象方法与C++语言描述)(第2版)》殷人昆——第三章
[2]《C/C++常用算法手册》秦姣华、向旭宇——第二章
[3]?百度搜索关键字:双栈
时间: 2024-11-05 17:26:30