在之前讲解了线性表的链式存储、顺序存储以及静态链表,循环链表和双向链表我们只需了解即可,接下来我们讲解线性表的应用“栈”
栈
栈是限定仅在表尾进行插入和删除操作的线性表
我们吧允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈我们称为空栈,栈又称为后进先出的线性表,简称为LIFO结构,可以理解为给枪的弹夹装子弹,后装的子弹会被先发射出去
既然栈是线性表的一种,线性表有顺序存储和链式存储两种结构,那么栈也就有这两种结构
栈的顺序存储结构
在栈的顺序存储中我们用下标为0的一端来作为栈底,定义一个变量top
变量来指示栈顶元素在数组中的位置,这个top就类似游标卡尺的游标,可以来回移动,top
的值必须小于栈的长度StackSize
,当栈存在一个元素时,top
等于0,因此通常把空栈的判定条件定位top
等于-1
栈的结构
# define MAXSIZE 1000
# define OK 1
# define ERROR 0
# define TRUE 1
# define FALSE 0
typedef int SElemType; //SElemType就是线性表中的元素的类型,这里设置为int
typedef int Status;
typedef struct{
SElemType data[MAXSIZE];
int top;
} SqStack;
进栈操作
Status Push(SqStack *S, SElemType e){
if(S->top == MAXSIZE - 1){ //栈满
return ERROR;
}
S->top++; //栈顶指针增加1
S->data[S->top] = e; //将新元素放入栈顶指针所指向空间中
return OK;
}
出栈操作
Status Pop(SqStack *S, SElemType *e){
if(S->top == -1){
return ERROR;
}
*e = S->data[S->top]; //取出栈顶元素
S->top--; //栈顶指针减少1
return OK;
}
进栈和出栈这两种操作都是将之前的线性表的顺序存储进行简单的改进,非常简单,这里不做过多讲解
两栈共享空间
栈的顺序存储非常方便,只从栈顶进栈和出栈,不存在插入数据后对后续数据的移动,但是和线性表的顺序存储存在相同的问题,就是栈的大小必须提前规定好,如果空间不够用了就必须使用编程手段来对空间进行扩充
如果现在有两个栈,可能会存在一种情况:一个栈已经满了,再存入数据就溢出了,而另外一个栈还有剩余的存储空间,我们怎样解决这样的问题?
我们可以使用一个数组来存储两个栈,但是需要一些小技巧:我们让数组的两个端点来分别作为两个栈的栈底,这样我们在两个栈中增加元素时两个栈顶指针就是从数组的两端点想中间移动,只要两个栈顶指针不相遇那么我们就可以一直向栈中存储数据
这里我们定义两个栈,分别为栈1和栈2,栈1为空时top1等于-1,栈2为空时top2等于n,n就是我们预先定义的数组长度