概念:
栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素,栈也称为后进先出表。
特点:
1. 栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针;
2. 限定性数据结构;
3. 栈可以用来在函数调用的时候存储断点,做递归时要用到栈。
种类:
栈可以用两种方式来实现,一种方法是用数组实现栈,这种栈成为静态栈;另外一种方法是用链表实现栈,这种栈叫做动态栈。
运算:
1. 设置一个空栈;
2. 插入一个新的栈顶元素;
3. 删除栈顶元素;
4. 读取栈顶元素;
5. 凡是对数据处理具有“后进先出”的特点,都可以用栈来操作。
存储结构(顺序栈、链栈):
1.顺序栈:用一组连续的存储单元存放从栈底到栈顶的数据元素,一般用一维数组表示,设置一个简单变量top指示栈顶位置,称为栈顶指针,它始终指向待插入元素的位置。
栈的上溢:
栈满时(top = stacksize),还有元素要进栈。
栈的下益:
栈空时(top = 0),还有元素要出栈。
2.链栈:用指针实现的栈叫链栈,栈的容量事先不能估计时采用的数据结构。
静态栈实现(C++):
stackLz.hxx文件
#ifndef STACKLZ_HXX
#define STACKLZ_HXX
#include <stdexcept>
template <class T, int MAXSIZE> class StackLz { // MAXSIZE由用户创建对象时自行设置
public:
StackLz(); // 构造函数
unsigned int stackLength() const; // 当前栈元素总数
void push(T const &); // 进栈, const &修饰是为了防止用户自定义的类型T过于庞大, 减小形参开销
void pop(); // 出栈
T top() const; // 返回栈顶元素
bool isEmpty() const; // 返回栈是否为空, const修饰是为了该方法不改变数据成员的值
bool isFull() const; // 返回栈是否已满
private:
T elems[MAXSIZE]; // 包含元素的数组
unsigned int numElems; // 元素的当前总个数
};
template <class T, int MAXSIZE>
unsigned StackLz<T, MAXSIZE>::stackLength() const {
return numElems;
}
template <class T, int MAXSIZE>
StackLz<T, MAXSIZE>::StackLz():numElems(0) { // 初始时栈为空
// do nothing
}
template <class T, int MAXSIZE>
void StackLz<T, MAXSIZE>::push(T const &elem) {
if(numElems == MAXSIZE) {
throw std::out_of_range("StackLz<>::push(): stack is full"); // 栈上溢
}
elems[numElems] = elem; // 附加元素
++numElems; // 增加元素的个数
}
template<class T, int MAXSIZE>
void StackLz<T, MAXSIZE>::pop() {
if (numElems <= 0) {
throw std::out_of_range("Stack<>::pop(): empty stack"); // 栈下溢
}
--numElems; // 减少元素的个数
}
template <class T, int MAXSIZE>
T StackLz<T, MAXSIZE>::top() const {
if (numElems <= 0) {
throw std::out_of_range("Stack<>::top(): empty stack");
}
return elems[numElems-1]; // 返回最后一个元素
}
template <class T, int MAXSIZE>
bool StackLz<T, MAXSIZE>::isEmpty() const {
return numElems == 0;
}
template <class T, int MAXSIZE>
bool StackLz<T, MAXSIZE>::isFull() const {
return numElems == MAXSIZE;
}
#endif
main.cpp文件
#include <iostream>
#include <string>
#include <cstdlib>
#include "stackLz.hxx"
using namespace std;
int main(int argc, char **argv)
{
try {
StackLz<int, 20> int20Stack; // 可以存储20个int元素的栈
StackLz<int, 40> int40Stack; // 可以存储40个int元素的栈
StackLz<string, 40> string40Stack; // 可存储40个string元素的栈
// 使用可存储20个int元素的栈
int20Stack.push(7);
cout << int20Stack.top() << endl; // 输出7
int20Stack.pop();
// 使用可存储40个string的栈
string40Stack.push("hello");
cout << string40Stack.top() << endl; // 输出hello
string40Stack.pop();
string40Stack.pop(); // Exception: Stack<>::pop<>: empty stack
return 0;
}
catch (exception const &ex) {
cerr << "Exception: " << ex.what() << endl;
return EXIT_FAILURE; // 退出程序且有ERROR标记
}
}
PS:使用非类型类模板自定义栈,且所有算法的时间复杂度都为O(1)。
栈的应用:
1. 子程序的嵌套调用;
2. 函数的递归实现;
3. 后缀表达式求值;
4. 中缀表达式转换成后缀表达式;
5. 二叉树非递归遍历;
6. 不胜枚举…=_=