1. 栈的基本概念
1.1 栈的定义
只允许在一端进行插入、删除操作的线性表
1.2 栈的特点
- LIFO:后进先出
- 最先进栈的元素,不一定是最后出栈,只限制了进栈的顺序,没有限制出栈的顺序
1.3 栈的基本说明
- 栈是一种线性表,栈元素具有线性关系,即前驱后继关系
- 栈顶(top):允许插入、删除的一端
- 栈底(bottom):不允许插入、删除的一端
- 空栈:不含任何元素的栈
2. 栈的顺序存储结构
2.1 顺序栈的实现
2.1.1 顺序栈的定义
栈的顺序存储的实现就是顺序栈,利用一组地址连续的存储单元存放自栈底到栈顶的数据元素。
2.1.2 栈的顺序存储类型描述
#define MaxSize 50 //栈中元素的最大个数
typedef struct{
ElemType data[MaxSize]; //用数组实现对栈中元素的存放
int top; //栈顶指针
}SqStack;
2.1.3 顺序栈的基本说明
- 栈空状态:s.top = -1;
- 栈满状态:s.top = MaxSize - 1;
- 元素进栈时:先栈顶指针加一,再送值入栈
- 元素出栈时:先取出栈顶元素,再栈顶指针减一
2.2 顺序栈的基本运算
2.2.1 初始化栈
实现思路
1. 将栈顶指针top置为 1
实现代码
//初始化顺序栈
void InitStack(SqStack *s){
s->top = -1;
}
2.2.2 判断栈空
实现思路
1. 先查看栈顶指针是否为 -1
2. 栈空返回 1 ,栈非空返回 0
实现代码
//判断栈空
int StackEmpty(SqStack s){
//判断栈顶指针是否为 -1
if(s.top == -1){
return 1;
}
else{
return 0;
}
}
2.2.3 进栈
实现思路
1. 判断栈是否已满
2. 栈不满时,先栈顶指针加一,再送值进栈
3. 进栈成功返回1,失败返回0
实现代码
//进栈
int Push(SqStack *s,int n){
int i,x;
//判断栈是否已满
if(s->top == MaxSize-1){
return 0;
}
//循环进栈
for(i = 0;i<n;i++){
scanf("%d",&x);
//先执行栈顶指针加一
++s->top;
//再送值入栈
s->data[s->top] = x;
}
return 1;
}
2.2.4 出栈
实现思路
1. 判断栈是否为空
2. 栈不为空,先取出栈顶元素,再执行栈顶指针减一
3. 出栈成功返回1 ,出栈失败返回 0
实现代码
//出栈
int Pop(SqStack *s,int n){
int i,x;
//判断栈是否为空
if(s->top == -1){
return 0;
}
//循环出栈
for(i=0;i<n;i++){
//先取出栈顶元素
x = s->data[s->top];
//再执行栈顶指针减一
s->top--;
printf("%d",x);
}
return 1;
}
2.2.5 读取栈顶元素
实现思路
1. 判断栈是否为空
2. 栈不为空,取出栈顶元素
实现代码
//读取栈顶元素
int GetTop(SqStack s,ElemType *x) {
//判断栈是否为空
if(s.top == -1){
return 0;
}
//取出栈顶元素
*x = s.data[s.top];
return 1;
}
3. 共享栈
3.1 共享栈的原理
- 栈的栈底时相对不变的,栈的栈顶再变化
- 将两个栈的栈底分别设置在一维数组的两端
- 两个栈的栈顶向共享空间的中间延伸
3.2 共享栈的特点
- 更有效的利用了存储空间
- 只有整个空间满时,才会发生上溢
- 存取数据的效率仍是O(1)
3.3 共享栈的基本说明
-
栈空:
- 0号栈:top0 == -1
- 1号栈:top1 == MaxSize
-
栈满:
- top1 = top0 + 1;
-
进栈
- 0号栈:先栈顶指针加一,再元素进栈
- 1号栈:先栈顶指针减一,再元素进栈
-
出栈
- 0号栈:先取出栈顶元素,栈顶指针减一
- 1号栈:先取出栈顶元素,栈顶元素加一
4. 栈的链式存储结构
4.1 链栈的定义
采用链式存储结构实现的栈
4.2 链栈的特点
- 便于多个栈共享空间、提高效率
- 不存在上溢情况
- 插入、删除结点方便
4.3 栈的链式存储类型描述
typedef struct LNode{
ElemType data; //数据域
struct LNode *next; //指针域
}LNode,*LinkStack; //栈类型定义
4.4 链栈的基本说明
- 栈空:lst -> next = NULL;
- 栈满:不存在栈满,无上溢
4.5 链栈的基本运算
4.5.1 初始化链栈
实现思路
1. 申请一个头结点
2. 头结点的指针域置空
实现代码
//初始化链栈
void InitStack(LNode *lst){
//申请头结点
lst = (LNode *)malloc(sizeof(LNode));
//指针域置空
lst->next = NULL;
}
4.5.2 判断栈空
实现思路
1. 头结点的指针域为空,则栈空
实现代码
//判断链栈是否为空
int IsEmpty(LNode lst){
//判断头结点的指针域是否为空
if(lst.next == NULL){
return 1;
}
else{
return 0;
}
}
4.5.3 进栈
实现思路
1. 使用头插法,将新的结点插入到头结点之后
实现代码
//入栈
void push(LNode *lst,ElemType x){
LNode *p;
//为新的结点申请空间
p = (LNode *)malloc(sizeof(LNode));
//为数据域赋值
p->data = x;
//将新插入的结点指向原来的栈顶结点
p->next = lst->next;
//头结点指向新入栈的结点
lst->next = p;
}
4.5.4 出栈
实现思路
1. 判断是否栈空
2. 栈不为空,返回出栈元素
实现代码
//出栈
int pop(LNode *lst,ElemType *x){
//判断链栈是否为空
if(lst->next == NULL){
return 0;
}
LNode *p;
//获取出栈结点
p = lst->next;
//获取出栈结点的数据域
*x = p->data;
//出去栈顶元素
lst->next = p->next;
//释放栈顶元素
free(p);
return 1;
}
4.5.5 获取栈顶元素
实现思路
1. 判断链栈是否为空
2. 链栈不为空,返回栈顶元素
实现代码
//获取栈顶元素
int GetTop(LNode *lst) {
//判断头结点的指针域是否为空
if(lst->next!=NULL){
return lst->next->data;
}
}
顺序栈整体代码下载地址:https://download.csdn.net/download/SoloVersion/13719735
链栈整体代码下载地址:https://download.csdn.net/download/SoloVersion/13719747
关注我的技术公众号,时常会有优质的技术文章推送。
微信扫一扫下方二维码即可关注: