栈的概念
栈又叫堆栈,是一种运算受限的线性表,只能在表尾进行插入或者删除,表尾这一断也称为栈顶,另一端称为栈底,插入一般称为入栈或者压栈,删除一般称为出栈。栈的特性就是“先进先出”,例如我把1,2先后压栈,出栈的时候必须先弹出2,才能弹出1。
注意:堆栈就是栈,而不是指堆和栈两种数据结构,还有,操作系统内存中的堆栈和数据结构中的堆栈是两回事。
栈的实现
栈可以用数组或者链表实现,用数组实现的称为顺序栈,用链表实现的称为链式栈,这里我实现的是顺序栈,主要的操作就是入栈和出栈,注意顺序栈还要支持动态扩容,而链表天然支持动态扩容所以链式栈不用考虑动态扩容。
template<typename DataType>
class stack {
public:
virtual int size() const= 0; //返回元素个数
virtual bool empty() const= 0; //栈是否为空
virtual void push(DataType data) = 0; //入栈
virtual DataType pop() = 0; //出栈
virtual DataType top() const= 0; //返回栈顶元素
};
template<typename DataType>
class ArrayStack : public stack<DataType> {
//注意这里stack也要有DataType
private:
DataType* array=nullptr;
int _size = 0; //实际存储的元素个数
int capacity = 32; //申请的空间大小
int _top = -1; //栈顶
public:
ArrayStack();
ArrayStack(const ArrayStack& as);
ArrayStack(DataType a[] , int n);
ArrayStack(std::vector<DataType>& v);
~ArrayStack();
int size() const;
bool empty() const;
void push(DataType data) ;
DataType pop();
DataType top() const;
DataType operator[](int index) const; //返回值是DataType,所以s[n]只能访问不能修改,后面const让const stack对象也能有一个访问的版本
void printStack();
private:
void make_space(int n); //扩容
};
这里定义了一个基类stack并用纯虚函数声明了一些必须实现的接口,有子类继承了stack就必须实现这几个接口。operator[]的重载可有可无,但是如果有返回值只能是DataType而不能是DataType&。
template<typename DataType>
void ArrayStack<DataType>::make_space(int n) {
if (array == nullptr)
array = new DataType[capacity];
if (capacity > n)
return;
while (capacity < n)
capacity <<= 1;
std::cout << "capacity : "<<capacity << std::endl;
DataType *tmp = new DataType[capacity];
for (int i = 0; i <= _top; i++)
tmp[i] = array[i];
delete[] array;
array = tmp;
}
先来看看扩容的函数,代码应该比较清晰,如果已经申请的容量capacity>要申请的容量n就直接返回,否则capacity就一直左移一位(乘2)直到大于等于n,然后重新申请capacity大小的空间,把旧空间的元素复制过去,然后释放旧空间。
template<typename DataType>
void ArrayStack<DataType>::push(DataType data) {
make_space(_size + 1);
array[++_top] = data;
++_size;
}
template<typename DataType>
DataType ArrayStack<DataType>::pop() {
if (_size == 0)
throw "stack is empty, no data to pop";
DataType data = array[_top--];
--_size;
return data;
}
入栈和出栈的逻辑也比较简单,需要注意入栈时需要判断是否需要扩容,出栈时需要判断栈是否为空。
完整代码
#ifndef STACK_H
#define STACK_H
#include <iostream>
#include <vector>
#include <assert.h>
template<typename DataType>
class stack {
public:
virtual int size() const= 0;
virtual bool empty() const= 0;
virtual void push(DataType data) = 0;
virtual DataType pop() = 0