栈
栈的定义:栈(stack)是限定仅在表位进行插入和删除操作的线性表。
允许插入和删除的一端被称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈又称为后进先出的线性表,简称为LIFO结构。
栈的抽象数据类型
注意:栈本身是一个线性表,所以线性表的顺序和链式存储他都适用。
一.顺序结构
用一个top变量来指示栈顶元素在数组中的位置,判定为栈空的条件是top==-1。
1.栈的结构定义
typedef int SElemType;//根据实际情况,不一定是int
typedef struct
{
SElemType data[MAXSIZE];
int top;
}SqStack;
进栈和出栈不在这里写了。
2.两栈共享空间
顺序存储结构有缺陷,那就是他必须在最开始就确定数组存储空间的大小,不够用只能靠编程手段来扩充容量。但对于两个相同类型的栈,我们可以最大限度的利用他们的空间来进行操作。
我们的做法是将一个栈的栈底作为数组的始端(下标为0处),另一个栈为数组的末端(下标为n-1处)我们假设这两个栈分别为栈1和栈2,top1和top2为他们的栈顶指针,只要这两个指针不见面,这两个栈就可以一直使用,如下所示
虽然这个图上看上去像两个不同的栈合并到了一起,要有两个数组。其实不然,这是在一个数组上进行操作的。
!!!这里有一点特别强调,判断栈1为空的条件只有top1==-1,判断栈2为空的条件只有top2 == n
判断他们栈满的条件是 top1 + 1 == top2
这个栈满中的栈指的是这个栈结构,不是单一的栈1或者栈2,栈1或者栈2满的条件是只要他们过了中间那处,他们就满了,当然top1==n-1是栈1也是满的,同理栈2也是。
两栈共享空间的结构如下:
typedef int Status
typedef struct
{
SElemType data[MAXSIZE];
int top1;
int top2;
}sqDoubleStack;
两栈共享空间的push方法,除了要插入的元素值参数外,还需要一个判断是栈1还是栈2的栈号参数stackNumber
push代码如下
Status Push(SqDoubleStack *S,SElemType e,int stackNumber)
{
if(S->top1+1==S->top2)//栈满,不能加新元素
return ERROR;
if(stackNumber==1)//栈1有元素进栈
S->data[++S->top1]=e;
else if(stackNumber==2)
S->data[--S->top2]=e;
return OK;
}
Pop代码如下
Status Pop(SqDoubleStack *S,SElemType e,int stackNumber)
{
if(stackNumber==1)
{
if(S->top1==-1) //说明栈1已经是空栈了
return ERROR;
*e=S->data[S->top1--]; //将栈1顶部元素出栈
}
else if(stackNumber==2)
{
if(S->top1==MAXSIZE) //说明栈1已经是空栈了
return ERROR;
*e=S->data[S->top2++]; //将栈1顶部元素出栈
}
return OK;
}
一般而言,使用这种数据结构,通常是当两个栈的空间需求有相反关系时,一方增一方减。除非情况特殊,一般不要使用,容易写混。
二.链式结构
栈的链式存储结构简称为链栈。
对于链栈来说是不需要头结点的,定义一个top指针,指向链栈的栈顶。对于空栈来说,链表原定义是头指针指向空,那么来链栈的空其实就是top==NULL的时候。
链栈的结构如下
ps.这里补充一下,这是我当时看到代码遇到的问题,是关于typedef后加指针的问题
这里的LinkStackPtr由他所定义的东西,相当于定义了一个指向struct stackNode结构的指针。
LinkStackPtr a等价于 struct stackNode *a
链式结构的进栈出栈操作如下图所示
进栈
出栈
最后总结一下,当元素个数不确定时最好用链栈,否则用顺序栈会好一些。
本片文章参考自《大话数据结构》程杰 清华大学出版社