概念
为什么使用堆栈?
用计算机进行表达式的求值时。
我们知道,算术表达式由两类对象构成:运算数和运算符号,但不同运算符的优先级不同。
对计算机来说,我们引入后缀表达式,比如abc*+de/-,我们平常所用的是中缀表示式,就是a+b*c-d/e,和前面的式子是一个意思。注意后缀的符号运算是从右向左的。
因此可以联想到“栈”,先放进去的数据,后拿出来。用一个表达式来理解:6 2 / 3 - 4 2 * + = ?首先在栈中依次放入6,2,遇到运算符“/”,出栈,依次拿出来2,6,进行运算得到结果3,放进栈中,再放入下一个数据3,遇到运算符“-”,再出栈,重复类似这样的过程。
复杂度是线性的,T(n)=O(n)。
堆栈的抽象数据类型描述:
是具有一定操作约束的线性表,只在一端(栈顶(Top)做插入(入栈push)、删除(出栈pop)
堆栈:Stack
操作集:长度为MaxSize的堆栈S,堆栈元素item属于ElementType
主要函数:
Stack CreateStack(int MaxSize);//生成空的堆栈,它的最大长度为Maxsize
int IsFull(Stack S,int MaxSize);//判断堆栈S是否已满
void Push(Stack S,ElementType item);//将元素item压入堆栈
int IsEmpty(Stack S);//判断堆栈S是否为空
ElementType Pop(Stack S);//删除并返回栈顶元素
栈的顺序存储实现
通常由一个一维数组(存储栈的元素)和一个记录栈顶元素(栈顶指针) 位置的变量组成。
#define MaxSize//储存数据元素的最大个数
typedef struct SNode *Stack;
struct SNode
{
ElementType Data[MaxSize];
int Top;
};
入栈和出栈的模板如下:
//入栈
void Push(Stack PtrS,ElementType item)
{
if(PtrS->Top==Maxsize-1)
{
cout<<"堆栈满";
return;
}else
{
PtrS->Data[++(PtrS->Top)]=item;
return;
}
}
//出栈
ElemenType Pop(Stack PtrS)
{
if(PtrS->Top==-1)
{
cout<<"堆栈空";
return ERROR;
}else
{
return (PtrS->Data[(PtrS->top)--]);
}
}
我们用一个例题理解一下吧^_^
【例题】用一个数组实现两个堆栈,最大利用数组空间,使数组只要有空间入栈就可以成功
思路:从栈的两头分别从中间生长,当两个栈的栈顶指针相遇,表示两个栈都满了。指针top1代表栈1的空间,而top2代表堆栈减去栈2剩下的空间,所以不可以用相加表示栈空间。
#define MaxSize<储存数据元素的最大个数>
struct DStack
{
ElementType Data[MaxSize];
int Top1;
int Top2;
}S;
S.Top1=-1;
S.Top2=Maxsize;
void Push(struct DStack *PtrS,ElementType item,int Tag)//Tag是区分两个堆栈的标志
{
if(PtrS->Top2-PtrS->Top1==1)
{
cout<<"堆栈满";
return;
}
if(Tag==1)
{
if(PtrS->Top1==-1)
{cout<<"堆栈1空";
return NULL;}else return PtrS->Data[(PtrS->Top1)--];
}else
{
if(PtrS->Top2==MaxSize)
{
cout<<"堆栈2空";
return NULL;
}else return PtrS->Data[(PtrS->Top2)++];
}
}
堆栈的链式存储实现
实际上就是一个单链表,叫做链栈。插入和删除操作只能在链栈的栈顶进行。