1.栈介绍
栈(stack)又称堆栈,其限制是仅允许在表的一端进行插入和删除操作。人们把此段成为栈顶,栈顶的第一个元素被称为栈顶元素,相对的,把另一端称为栈底元素。向一个栈插入新元素又称为进栈或入栈,它是把该元素放到栈顶元素上面,使之成为新的栈顶元素;从一个栈删除元素又称为出栈或退栈,它是把栈顶元素删除掉,使其下面相邻的元素成为新的栈顶元素。由于堆栈数据结构只允许在一端进行操作,因而按照后进先出(LIFO,Last In First Out)的原理运作。
操作集:长度为MaSize的堆栈 S∈Stack,堆栈元素item∈ElementType
1)、Stack CreateStack(int MaxSize): 生成空堆栈,其最大长度为MaxSize;
2)、int IsFull(Stack S, int MaxSize): 判断堆栈S是否已满;
3)、void Push(Stack S, ElementType item):将元素item压入栈;
4)、int IsEmpty(Stack S): 判断堆栈S是否为空;
5)、ElementType Pop(Stack S):删除并返回栈顶元素
6)、ElementType Top(Stack S):返回但不删除栈顶元素
7)、int Size(Stack S): 返回栈内元素的个数
2.栈的应用:算术表达式的计算
1)中缀表达式和后缀表达式
中缀表达式的计算比较复杂,既要考虑括号的作用,又要考虑运算符的优先级,还要考虑运算符出现的先后顺序。因此,各运算符实际运算次序往往同它们在表达式中出现的先后顺序是不一致的,
采用后缀表示的算术表达式被称为后缀算术表达式或后缀表达式。在后缀表达式中,不存在括号,也不存在优先级的差别,计算过程完全按照运算符出现的先后次序进行,整个计算过程仅需一遍扫描便可完成。
中缀表达向后缀表达式转换需要用到栈,具体过程如下:
设置两个栈来实现,stack栈用来存放运算符,post栈用来存放最后的后缀表达式。
在将中缀表达式转换为后缀表达式时,其转换原则是:从左到右扫描中缀表达式,若读到的是操作数,直接存入post栈,若读到的是运算符:
(1)该运算符是“(”,则直接存入stack栈;
(2)该运算符是“)”,则将stack栈中第一个“(”前的所有运算符依次出栈,并依次存入post栈, 但“(”与“)”都不存入post栈;
(3)若该运算符为非括号,则将共运算符和stack栈顶元素相比较:若高于或等于栈顶元素运算符,则直接存入stack栈,否则将栈顶元素出栈,存入post栈。当扫描完后,stack栈中还有运算符时,则将所有的运算符出栈,存入post栈。
例如:中缀表达式A+B*(C-D)-E/F所对应的的后缀表达式为ABCD-*+EF/-。
过程:首先两个栈stack和post,A入post -> “+“入stack -> B入post -> “*”入stack -> “(”入stack -> C入post -> "-"入stack -> D入post ->"-"出stack并入post -> “(”出stack -> "*"出stack并入post -> "+"出stack并入post -> "-"入stack -> E入post -> "/"入stack -> F入post -> “/”出stack并入post -> "-"出stack并入post
2)后缀表达式的求值
通过后缀表示计算表达式值的过程为:
顺序扫描表达式的每一项,然后根据它的类型做如下相应操作:如果该项是操作数,则将其压入栈中;如果该项是操作符<op>,则连续从栈中退出两个操作数Y和X,形成运算符指令X<op>Y,并将计算结果重新压入栈中。当表达式的所有项都扫描并处理完后,栈顶存放的就是最后的计算结果。
3.写一个函数将栈里的元素升序排列。栈的实现未知,算法只能借助栈完成,可使用的函数有push,pop,top,empty等。
思路:可借助另一个栈来完成排序,从原始栈里一次弹出元素放入辅助栈里,每当将要压入的元素使得辅助栈不是升序排列,就将辅助栈里的元素重新压入原始栈,直到辅助栈里的元素都小于当前要压入的元素,然后再压入当前的元素。
#include<stack>
stack<int> sort(stack<int> s)
{
stack<int> r;
while (!s.empty())
{
int tmp = s.top();
s.pop();
while (!r.empty() && r.top() > tmp)
{
s.push(r.top());
r.pop();
}
r.push(tmp);
}
return r;
}
4.如何用两个栈实现队列的功能?
思路:假设有两个栈stack1和stack2,则stack1保存刚刚入队的元素,若需出队且stack2为空,则将stack1中所有元素压入stack2中(此时stack2中的元素顺序为元素入队顺序),然后取出stack2的栈顶元素即可,若stack2非空(此时stack2中元素为stack1之前压入,其栈顶元素就是最先入队的元素),直接取出stack2栈顶元素即可。
template <class T> class MyQueue
{
stack<T> stack1, stack2;
public:
MyQueue() {}
int size()
{
return stack1.size() + stack2.size();
}
bool empty()
{
if (size() == 0)
return true;
else
return false;
}
void push(T value)
{
stack1.push(value);
}
T front()
{
if (!stack2.empty())
return stack2.top();
while (!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
return stack2.top();
}
void pop() {
if (stack2.empty())
{
while (stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
}
stack2.pop();
}
};