栈的简单理解和基本操作

在这里插入图片描述

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 顺序栈的基本说明

  1. 栈空状态:s.top = -1;
  2. 栈满状态:s.top = MaxSize - 1;
  3. 元素进栈时:先栈顶指针加一,再送值入栈
  4. 元素出栈时:先取出栈顶元素,再栈顶指针减一
    在这里插入图片描述

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

关注我的技术公众号,时常会有优质的技术文章推送。
微信扫一扫下方二维码即可关注:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/SoloVersion/article/details/111354248