本文有关栈的介绍部分参考自网站数据结构。
1. 栈
1.1 栈的定义
栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表。
(1)通常称插入、删除的这一端为栈顶(Top),另一端称为栈底(Bottom)。
(2)当表中没有元素时称为空栈。
(3)栈为后进先出(Last In First Out)的线性表,简称为LIFO表。
栈的修改是按后进先出的原则进行。每次删除(退栈)的总是当前栈中"最新"的元素,即最后插入(进栈)的元素,而最先插入的是被放在栈的底部,要到最后才能删除。
【示例】元素是以a1,a2,…,an的顺序进栈,退栈的次序却是an,an-1,…,a1。
1.2 栈的运算
(1)initStack(S)
构造一个空栈S。
(2)isEmpty(S)
判栈空。若S为空栈,则返回TRUE,否则返回FALSE。
(3)isFull(S)
判栈满。若S为满栈,则返回TRUE,否则返回FALSE。
注意:
该运算只适用于栈的顺序存储结构。
(4)push(S,x)
进栈。若栈S不满,则将元素x插入S的栈顶。
(5)pop(S)
退栈。若栈S非空,则将S的栈顶元素删去,并返回该元素。
(6)top(S)
取栈顶元素。若栈S非空,则返回栈顶元素,但不改变栈的状态。
2. 栈的三种实现
我在实现的时候,栈的基本函数都有(isEmpty、push、pop、top)。因为我是用面向对象的方法来设计栈,所以栈的初始化、拷贝构造、赋值运算符重载等也都具备。另外,我采取了C++中的模板类来设计栈,使得该栈设计能适应更多的场合。
2.1 基于静态数组
基于静态数组的栈的最大特点就是栈的大小是固定的,用户在初始化之后就无法改变。在编译期,编译器就已经给这个栈分配好内存,在“内存的栈”上分配。
这是我所设计的栈模板类:
1 template<class T, int defCapacity = 1024> 2 class Stack 3 { 4 public: 5 Stack(); 6 virtual ~Stack(); 7 bool isEmpty(); 8 bool push(T val); // 进栈。若栈不满,则将元素插入栈顶。 9 T top(); // 取栈顶元素。若栈S非空,则返回栈顶元素,但不改变栈的状态。 10 bool pop(); // 退栈。若栈非空,则将栈顶元素删去,并返回是否退栈成功的标志。 11 // 这里没有采用返回被删栈顶元素的原因在于这里写的是一个模板, 12 // 当栈为空的时候不方便返回。当然,这个问题是可以通过断言或 13 // 抛异常来解决的。具体做法可根据具体情况来定。 14 int getSizeOfStack(); 15 16 private: 17 T stack[defCapacity]; 18 int sizeOfStack; 19 20 };
具体实现代码为:
1 #include <iostream> 2 #include <cassert> 3 using namespace std; 4 5 // const int CAPACITY = 1024; 6 7 template<class T, int defCapacity = 1024> 8 class Stack 9 { 10 public: 11 Stack(); 12 virtual ~Stack(); 13 bool isEmpty(); 14 bool push(T val); // 进栈。若栈不满,则将元素插入栈顶。 15 T top(); // 取栈顶元素。若栈S非空,则返回栈顶元素,但不改变栈的状态。 16 bool pop(); // 退栈。若栈非空,则将栈顶元素删去,并返回是否退栈成功的标志。 17 // 这里没有采用返回被删栈顶元素的原因在于这里写的是一个模板, 18 // 当栈为空的时候不方便返回。当然,这个问题是可以通过断言或 19 // 抛异常来解决的。具体做法可根据具体情况来定。 20 int getSizeOfStack(); 21 22 private: 23 T stack[defCapacity]; 24 int sizeOfStack; 25 26 }; 27 28 29 template<class T, int defCapacity> 30 Stack<T, defCapacity>::Stack() 31 { 32 sizeOfStack = 0; 33 } 34 35 template<class T, int defCapacity> 36 Stack<T, defCapacity>::~Stack() 37 { 38 39 } 40 41 template<class T, int defCapacity> 42 bool Stack<T, defCapacity>::isEmpty() 43 { 44 return sizeOfStack == 0; 45 } 46 47 template<class T, int defCapacity> 48 bool Stack<T, defCapacity>::push(T val) 49 { 50 // assert(sizeOfStack < defCapacity); 51 bool isSuccess = true; 52 if (sizeOfStack == defCapacity) 53 { 54 cerr << "There is no space for new elements." << endl; 55 isSuccess = false; 56 } 57 else 58 { 59 stack[sizeOfStack] = val; 60 sizeOfStack++; 61 } 62 return isSuccess; 63 } 64 65 template<class T, int defCapacity> 66 T Stack<T, defCapacity>::top() 67 { 68 return stack[sizeOfStack - 1]; 69 } 70 71 template<class T, int defCapacity> 72 bool Stack<T, defCapacity>::pop() 73 { 74 // assert(sizeOfStack > 0); 75 bool isSuccess = true; 76 if (sizeOfStack == 0) 77 { 78 cerr << "There is no element in stack." << endl; 79 isSuccess = false; 80 } 81 else 82 { 83 sizeOfStack--; 84 } 85 return isSuccess; 86 } 87 88 template<class T, int defCapacity> 89 int Stack<T, defCapacity>::getSizeOfStack() 90 { 91 return sizeOfStack; 92 }