栈: 后进先出LIFO线性表
栈的逻辑结构
限制仅在表的一端进行插入和删除的线性表
栈顶 ( top ) 栈底 ( bottom )
空栈 :top=-1
存取原则 后进先出 (LIFO)
- 置空栈SetNull(S) :将栈S置成空栈。
- 入栈Push (S, x) :将元素x插入到栈S的栈顶。
- 出栈PoP(S) : 删除栈S的栈顶元素。
- 取栈顶元素GetTop (S):返回栈S的栈顶元素,栈顶元素并不出栈。
- 判栈空Empty(S) :判别栈S是否为空。
栈的顺序存储结构——顺序栈
一般用数组的开始一端表示栈底,同时附设指针top指示栈顶元素在数组中的位置。
实现
const int StackSize = 1024; //定义栈的最大高度
template <class T>
class SeqStack //定义顺序栈模板类
{
public:
SeqStack() { top = -1; } //构造函数,初始化空栈
void Push(T x); //入栈操作
T Pop(); //出栈操作
T GetTop(); //查找栈顶元素
bool Empty(); //判别栈是否为空
private:
T data[StackSize]; //定义数组
int top; //栈顶指针
};
入栈操作
//入栈操作
template <class T>
void SeqStack<T>::Push(T x) {
if (top >= StackSize - 1) throw "上溢";
top++;//栈顶指针上移
data[top] = x;
}
查找栈顶元素
//查找栈顶元素
template <class T>
T SeqStack<T>::GetTop() {
if (Empty()) throw "下溢";
return data[top];
}
出栈操作
//出栈操作
template <class T>
T SeqStack<T>::Pop() {
if (Empty()) throw "下溢";
top--;//栈顶指针下移
return data[top + 1];
}
栈的链式存储结构
栈顶:单链表的头部最容易操作,栈顶设在头部
不需要头结点
实现
template <class T>
struct Node
{
T data;
struct Node <T> * next;
};
template <class T>
class LinkStack //定义链栈模板类
{
public:
LinkStack() { top = NULL; } //构造函数,初始化空栈
~LinkStack(); //析构函数
void Push(T x); //入栈操作
T Pop(); //出栈操作
T & GetTop(); //查找栈顶元素
bool Empty() { return (NULL == top) ? true : false; }//判栈空
private:
struct Node <T> * top; //栈顶指针
};
入栈操作
template <class T>
void LinkStack<T>::Push(T x)
{
struct Node <T> * p = new Node<T>; //①
p->data = x;
p->next = top; //②
top = p; //③
}
出栈操作
template <class T>
T LinkStack<T>::Pop()//出栈操作
{
if (Empty()) throw "下溢";
T x = top->data; //①
struct Node <T> * p = top; //②
top = top->next; //③
delete p; //④,释放原栈顶结点
return x;
}
顺序栈与链栈的比较
时间耗费 :O(1)
空间耗费:
顺序栈的预分配,导致空间浪费
链栈的指针域,有额外开销
练习:
设计算法,把十进制数转换为二进制输出
void numConvert(int num, int r)
{
LinkStack<int> s; //初始化栈
int top = -1;
while (num != 0)
{
s.Push(num%r); //余数入栈
num = num / r;
}
while (!s.Empty()) cout << s.Pop(); //出栈打印
}