数据结构的C++实现之栈-顺序栈
注:本文为清华大学计算机系列教材《数据结构》-殷人昆-第2版的学习笔记
栈的定义
栈(STACK)定义为只允许在表的末端进行插入和删除的线性表.允许插入和删除的一端叫做栈顶(top),而不允许插入和删除的另一端叫做栈底(bottom),当栈中没有任何元素时称为空栈.栈对数据存取的特点是"先进后出".
顺序栈
栈的抽象数据类型有两种典型的存储表示:基于数组的存储表示和基于链表的存储表示.基于数组的存储表示实现的栈称为顺序栈,基于链表的存储表示实现的栈称为链式栈.
下面的程序使用的是一维数组作为栈的存储空间,存放栈元素的数组的头指针为*elements,该数组的最大允许存放元素个数为maxSize,当前栈顶位置由数组下标指针top指示.栈不空时,elements[0]是栈中的第一个元素.
顺序栈的抽象基类头文件
//顺序栈的抽象基类stack.h
#ifndef __STACK_H__
const int maxSize = 50;
using namespace std;
template<class T>
class Stack{ // 栈的类定义
public:
Stack(){}; // 构造函数
virtual void Push(const T& x)=0; // 新元素x进栈
virtual bool Pop(T& x) = 0; // 栈顶元素出栈,由x返回
virtual bool getTop(T& x)const = 0; // 读取栈顶元素,由x返回
virtual bool IsEmpty()const = 0; // 判断栈空否
// virtual bool IsFull()const = 0; // 判断栈满否
virtual int getSize()const = 0; // 计算栈中元素个数
};
#endif
顺序栈的头文件
// 顺序栈的头文件SeqStack.h
# include <assert.h>
# include <iostream>
# include "stack.h"
template <class T>
class SeqStack:public Stack<T> { // 顺序栈的类定义
public:
SeqStack(int sz = 50); // 建立一个空栈
~SeqStack(){delete[]elements;} // 析构函数
void Push(const T& x);
// 如果IsFull(),则溢出处理,否则把x插入到栈的栈顶
bool Pop(T& x);
// 如果IsEmpty(),则不执行退栈,返回false,否则退掉位于栈顶的元素,返回true
// 退出的元素值通过引用型参数x返回
bool getTop(T& x)const;
// 如果IsEmpty(),则返回false,否则返回true,并通过引用型参数x得到栈顶元素x的值
bool IsEmpty()const {return (top == -1)?true:false;}
bool IsFull()const {return (top == maxSize - 1)?true:false;}
// 如果栈中元素个数等于maxSize,则返回true,否则返回false
int getSize()const {return top+1;} // 函数返回栈顶中元素个数
void MakeEmpty(){top = -1;} // 清空栈的内容
template<typename T1>
friend ostream& operator<<(ostream& os,SeqStack<T1>& s);
// 输出栈中元素的重载操作<<
private:
T * elements; // 存放栈中元素的栈数组
int top; // 栈顶指针
int maxSize; // 栈最大可容纳元素个数
void overflowProcess(); // 栈的溢出处理
};
顺序栈的具体实现文件
// SeqStack.cpp
# include "SeqStack.h"
template <class T>
SeqStack<T>::SeqStack(int sz):top(-1),maxSize(sz){
// 建立一个最大尺寸为sz的空栈,若分配不成功则错误处理
elements = new T[maxSize]; // 创建栈的数组空间
assert(elements != NULL); // 断言:动态存储分配成功与否
};
const int stackIncreament = 20; // 栈溢出时扩展空间的增量
template <class T>
void SeqStack<T>::overflowProcess(){
// 私有函数:扩展栈的存储空间
cout << "溢出处理中....."<<endl;
T * newArray = new T[maxSize + stackIncreament];
if(newArray == NULL){cerr<<"存储分配失败!"<<endl;exit(1);}
for(int i = 0;i <= top; i++)
newArray[i] = elements[i];
maxSize = maxSize + stackIncreament;
delete []elements;
elements = newArray;
cout << "溢出处理完毕"<<endl;
};
template<class T>
void SeqStack<T>::Push(const T& x){
// 公共函数:若栈不满,则将元素x插入到该栈的栈顶,否则溢出处理
if(IsFull()==true)
overflowProcess(); // 判栈空否,若栈空则函数返回
elements[++top] = x;
};
template <class T>
bool SeqStack<T>::Pop(T& x){
// 公共函数:若栈不空则函数返回该栈栈顶元素的值,然后栈指针退1
if(IsEmpty() == true) return false; // 判栈空否,若栈空则函数返回
x = elements[top--]; // 栈顶指针退1
return true; // 退栈成功
};
template<class T>
bool SeqStack<T>::getTop(T& x)const{
// 公共函数:若栈不空则函数返回该栈栈顶元素的地址
if(IsEmpty() == true) return false;
x = elements[top];
return true;
};
template<class T>
ostream& operator<<(ostream& os,SeqStack<T>& s){
// 输出栈中元素的重载操作<<
os << "top="<<s.top<<endl; // 输出栈顶位置
for(int i = 0;i <= s.top; i++)
os << i << ":"<<s.elements[i] << endl;
return os;
};
int main(){
SeqStack<int> seqstack(3); // 初始化栈的空间为3
int m;
int j;
seqstack.Push(3); // 压栈
seqstack.Push(10);
seqstack.Push(8);
seqstack.Push(4);
seqstack.Push(7); // 连续的入栈操作,期间经过溢出处理
seqstack.Pop(m);
seqstack.getTop(j); // 栈顶元素的值
cout << "弹出的元素值是:"<< m <<endl;
cout << "栈顶元素的值为:"<<j<<endl;
return 0;
}