4.1 栈的顺序存储结构
文章目录
4.1.1 栈的简介
栈是一种只允许在一端进行插入或者删除的线性表,形象一点,我们大家都知道手枪弹夹吧,类似下图这种:

这里面子弹都是一发发装进去的,就像栈的插入,只从一端,当射击时,后面装的子弹先射击出去,就像栈的出栈。栈这个词听起来可能挺玄乎的,但是他其实就好比手枪弹夹这种结构,是一种"后进先出"(Last In First Out,LIFO)的操作方式。
4.1.2 栈的顺序结构定义
一个栈我们需要存数据还要有一个能指示栈顶的指针,我们就用data[]数组存放数据,top用于指向栈顶元素。代码如下:
/*定义栈类型*/
typedef struct{
SElemType data[MAXSIZE];
int top; //栈顶指针
}SqStack;
同时,栈空的时候我们使top=-1,栈满时top=MAXSIZE-1。
以下是栈的示意图:

现在我们有栈这个结构了,我们该想想有哪些操作了,例如删除,插入,清除之类的,下面是会涉及到操作函数的表格:
| 操作函数 | 操作结果 |
|---|---|
| InitStack(SqStack *S) | 初始化栈 |
| ClearStack(SqStack *S) | 清空栈 |
| StackEmpty(SqStack S) | 判断栈是否为空 |
| GetTop(SqStack S,SElemType *e) | 获取栈顶元素,用e返回 |
| Push(SqStack *S,SElemType e) | 进栈 |
| Pop(SqStack *S,SElemType *e) | 出栈,并将数据存入e |
| StackLength(SqStack S) | 返回栈长度 |
| StackTraverse(SqStack S) | 遍历并且打印栈 |
4.1.3 入栈和出栈
入栈
入栈就像将子弹一颗颗装入弹夹中,图解如下:

- 首先要判断栈是否满,即
S->top=MAXSIZE-1为栈满,不可入栈 - 然后先将栈顶指针
top移动一位到空位置,即S->top++ - 最后利用栈顶指针来为空位置赋值
S->data[S->top]=e
代码实现:
/*进栈,将新元素e放入栈顶*/
Status Push(SqStack *S,SElemType e){
if(S->top==MAXSIZE-1) //栈满
return ERROR;
S->top++; //将栈顶移到空的位置
S->data[S->top] = e; //插入元素e到栈顶
}
出栈
出栈就像子弹发射出去,后进的先出,图解如下:

- 首先判断栈是否为空,即
S->top=-1时栈空,不可出栈。 - 再将要删除的栈顶元素数据赋值给指针e
- 最后将栈顶指针向栈底移动一位。
代码实现:
/*出栈,将出去的元素存入e*/
Status Pop(SqStack *S,SElemType *e){
//判断栈是否为空
if(S->top == -1)
return ERROR;
*e = S->data[S->top]; //将栈顶元素存入e
S->top--; //栈顶指针top减1
return OK;
}
4.1.3 获得栈顶元素
根据栈的结构,我们可以很轻易得知,获得栈顶元素,只要根据栈顶指针去获得就可以了,下面给出代码:
/*若栈存在且非空,用e返回栈顶元素*/
Status GetTop(SqStack S,SElemType *e){
if(S.top == -1){
return ERROR;
}else{
*e = S.data[S.top];
}
return OK;
}
千万要注意首先判断栈是否非空。
4.1.4 初始化栈和清空栈
初始化栈
初始化栈,实现这个功能非常容易,只要让栈顶指针指向-1即可,S->top=-1,表示建立了一个空栈。
代码实现:
/*初始化栈*/
Status InitStack(SqStack *S){
S->top = -1;
return OK;
}
清空栈
清空栈在栈的顺序结构中和初始化栈一样。
代码实现:
/*清空栈*/
Status ClearStack(SqStack *S){
S->top = -1;
return OK;
}
4.1.5 其他剩余操作
剩余的操作都很好理解,附上代码~
获取栈长度
/*返回栈长度*/
int StackLength(SqStack S){
return S.top+1; //栈顶+1就是栈长度
}
判断栈是否为空
/*判断栈是否为空*/
Status StackEmpty(SqStack S){
if(S.top==-1)
return True;
else
return False;
}
遍历并打印栈
/*打印栈*/
Status visit(SElemType c){
printf("%d ",c);
return OK;
}
Status StackTraverse(SqStack S){
int i = 0;
while(i<=S.top){
visit(S.data[i]);
i++;
}
}
4.1.6 测试
测试代码:
int main(){
int j;
SqStack s;
int e;
if(InitStack(&s)==OK)
for(j=1;j<=10;j++)
Push(&s,j);
printf("栈中元素依次为:");
StackTraverse(s);
Pop(&s,&e);
printf("弹出的栈顶元素 e=%d\n",e);
printf("栈空否:%d(1:空 0:否)\n",StackEmpty(s));
GetTop(s,&e);
printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
ClearStack(&s);
printf("清空栈后,栈空否:%d(1:空 0:否)\n",StackEmpty(s));
system("pause");
return 0;
}
运行结果:
栈中元素依次为:1 2 3 4 5 6 7 8 9 10 弹出的栈顶元素 e=10
栈空否:0(1:空 0:否)
栈顶元素 e=9 栈的长度为9
清空栈后,栈空否:1(1:空 0:否)
请按任意键继续. . .
4.1.7 完整代码
下面附上完整代码:
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
#define True 1
#define False 0
#define MAXSIZE 20
typedef int SElemType;
typedef int Status;
/*定义栈类型*/
typedef struct{
SElemType data[MAXSIZE];
int top; //栈顶指针
}SqStack;
/*初始化栈*/
Status InitStack(SqStack *S){
S->top = -1;
return OK;
}
/*清空栈*/
Status ClearStack(SqStack *S){
S->top = -1;
return OK;
}
/*判断栈是否为空*/
Status StackEmpty(SqStack S){
if(S.top==-1)
return True;
else
return False;
}
/*若栈存在且非空,用e返回栈顶元素*/
Status GetTop(SqStack S,SElemType *e){
if(S.top == -1){
return ERROR;
}else{
*e = S.data[S.top];
}
return OK;
}
/*进栈,将新元素e放入栈顶*/
Status Push(SqStack *S,SElemType e){
if(S->top==MAXSIZE-1) //栈满
return ERROR;
S->top++; //将栈顶移到空的位置
S->data[S->top] = e; //插入元素e到栈顶
}
/*出栈,将出去的元素存入e*/
Status Pop(SqStack *S,SElemType *e){
//判断栈是否为空
if(S->top == -1)
return ERROR;
*e = S->data[S->top]; //将栈顶元素存入e
S->top--; //栈顶指针top减1
return OK;
}
/*返回栈长度*/
int StackLength(SqStack S){
return S.top+1;
}
/*打印栈*/
Status visit(SElemType c){
printf("%d ",c);
return OK;
}
Status StackTraverse(SqStack S){
int i = 0;
while(i<=S.top){
visit(S.data[i]);
i++;
}
}
int main(){
int j;
SqStack s;
int e;
if(InitStack(&s)==OK)
for(j=1;j<=10;j++)
Push(&s,j);
printf("栈中元素依次为:");
StackTraverse(s);
Pop(&s,&e);
printf("弹出的栈顶元素 e=%d\n",e);
printf("栈空否:%d(1:空 0:否)\n",StackEmpty(s));
GetTop(s,&e);
printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
ClearStack(&s);
printf("清空栈后,栈空否:%d(1:空 0:否)\n",StackEmpty(s));
system("pause");
return 0;
}
4.1.8 栈顺序结构的优缺点
优点:
- 实现简单,存储结构紧凑,空间利用率高;
- 访问元素快速,时间复杂度为O(1),无需遍历;
- 可以使用下标随机访问栈中的元素,方便实现一些操作,如查找指定元素、修改栈中的元素等;
- 操作系统通常会为每个线程分配一个栈,用于保存线程的状态和局部变量。在栈顺序结构中,可以通过指定栈的大小来限制函数调用的嵌套深度,防止栈溢出。
缺点:
- 栈顺序结构的大小是固定的,一旦初始化后就无法动态调整大小,可能会浪费内存或导致栈溢出;
- 在入栈和出栈操作时,需要移动元素,时间复杂度为O(n),当栈中元素较多时,效率会降低;
- 栈的容量可能会受到操作系统的限制,当栈的大小超过操作系统限制时,会导致栈溢出;
- 如果栈中的元素是复杂类型,需要进行深拷贝,可能会消耗较多的时间和内存。

2506

被折叠的 条评论
为什么被折叠?



