数据结构——栈和队列

目录

1.栈

1.1栈的基本概念

1.2栈的顺序存储实现

1.3共享栈

1.4栈的链式存储实现

1.5栈在括号匹配中的应用

1.6栈在表达式求值中的应用

1.6.1中、前、后缀表达式

1.6.2后缀表达式⭐(中转后:手算+机算;后缀求值:手算+机算)

1.6.3前缀表达式(中转前:手算;前缀求值:机算⭐)

1.6.4中缀表达式(中缀求值:机算)

1.7栈在递归中的应用

2.队列

2.1队列的基本概念

2.2队列的顺序存储实现

2.3小结

2.3队列的链式存储实现

2.4双端队列

2.5队列的应用

3.特殊矩阵的压缩存储

3.1数组的存储结构

3.2特殊矩阵


栈和队列都是操作受限制的线性表。

1.栈

1.1栈的基本概念

栈(stack):只能在一端进行(栈顶)插入/删除的线性表。故其逻辑结构为线性结构(一对一)

线性表:具有相同数据类型的n个数据元素的有限序列。

栈的特点:后进先出(LIFO)

基本操作:

InitStack(&S)    //初始化栈。构造一个空栈S,分配内存空间。
DestroyStack(&S) //销毁栈。销毁并释放栈S所占用的内存空间。
Push(&S,x)       //进栈,若栈S未满,则将x加入使之成为新栈顶。
Pop(&S,&x)       //出栈,若栈S非空,则弹出栈顶元素,并用x返回。
GetTop(S,&x)     //读栈顶元素。若栈S非空,则用x返回栈顶元素
StackEmpty(S)    //判断一个栈S是否为空。若S为空,则返回true,否则返回false 

 常考题型:已知进栈顺序,有哪些合法的出栈顺序?

n个不同元素进栈,出栈元素不同排列顺序个数为:\frac{1}{n+1}C_{2n}^{n}(卡特兰数Catalan),可用数学归纳法证明(不要求掌握)

1.2栈的顺序存储实现

顺序栈:逻辑结构——线性结构;存储结构(物理结构)——顺序存储

顺序栈的定义:

//顺序栈的定义:
#define maxsize 10 
typedef struct {
	ElemType data[maxsize]; //数据域(静态分配:静态数组) 
	int top;				//栈顶指针( 实际指的是该静态数组的数组下标,起到指针的作用) 
}SqStack; //sequence stack

基本操作1(top== -1时,即栈顶指针始终指向非空区域

顺序栈的初始化:

void InitStack(SqStack &S){
	S.top = -1; //设定-1代表空栈 
} 

SqStack S; 声明一个顺序栈后,分配了连续的存储空间,大小为maxsize×sizeof(ElemType) 

//栈空判断
bool StackEmpty(SqStack S){
	if(S.top == -1) return true;
	else return false;
} 

顺序栈的进栈操作(增):

bool Push(SqStack &S,ElemType x){
	if(S.top == maxsize-1) return false; //栈满,无法再入栈,报错
//	S.top = S.top + 1; //先移动栈顶指针 
//	S.data[S.top] = x; //新元素再入栈 
	S.data[++S.top] = x; //等价为一句 (top先加再用) 
	return true;
}

顺序栈的出栈操作(删):

bool Pop(SqStack &S,ElemType &x){
	if(S.top == -1) return false;
//	x = S.data[S.top]; //先删除元素,并由x代回 
//	S.top = S.top - 1; //再移动栈顶指针 
	x = S.data[S.top--]; //等价为一句 (top先用再减)
	return true;	
} 

读栈顶元素操作(查):

ElemType GetTop(SqStack S){
	if(S.top == -1) return false; //栈空,报错 
	return S.data[S.top];
} 
bool GetTop(SqStack S,ElemType &x){
	if(S.top == -1) return false; //栈空,报错 
	x = S.data[S.top];
	return true;
} 

基本操作2(top== 0时,即栈顶指针始终指向下一个可插入的空区域

顺序栈的初始化:

void InitStack(SqStack &S){
	S.top = 0; //设定0代表空栈 
}
//判空 
bool StackEmpty(SqStack S){
	if(S.top == 0) return true;
	else return false;
}

顺序栈的进栈操作(增):

bool Push(SqStack &S,ElemType x){
	if(S.top == maxsize) return false;
	S.data[S.top++] = x; //top先用再加 
	return true;
}

顺序栈的出栈操作(删):

bool Pop(SqStack &S,ElemType &x){
	if(S.top == 0) return false;
	x = S.data[--S.top];//top先减再用 
	return true;
}

读顺序栈的栈顶元素的操作(查):

bool GetTop(SqStack S,ElemType &x){
	if(S.top == 0) return false;
	x = S.data[--S.top];
	return true;
}

top == -1 和 top == 0 的区别:(注意审题)

比较项

top == -1 

栈顶指针始终指向非空区域

top == 0 

栈顶指针始终指向下一个可插入的空区域

栈空 top == -1 top == 0
栈满 top == maxsize -1 top == maxsize
push S.top先加再用       S.top先用再加
pop S.top先用再减       S.top先减再用

1.3共享栈

共享栈:两个栈共享同一片存储空间。

定义与初始化:

//定义 
#define maxsize 10
typedef struct{
	ElemType data[maxsize];
	int top0;  //0号栈栈顶指针
	int top1;  //1号栈栈顶指针 
}ShStack;      //shared stack 
//初始化 
void InitShStack(ShStack &S){
	//共享栈所占空间的头尾分别作为栈顶指针
	S.top0 = -1;
	S.top1 = maxsize;
} 

栈满条件:top0+1 == top1  

栈的销毁?——系统包分配包回收

在声明栈(Stack S)时,系统自动给栈分配空间;在所在生命域的生命周期结束后(如所在函数运行结束后),系统自动回收内存。 

而上述中 top == -1 或 top == 0;都是在逻辑上的销毁。

1.4栈的链式存储实现

链栈:逻辑结构——线性结构;存储结构(物理结构)——链式存储

进栈/出栈只能在链栈的一端(栈顶)进行的单链表

链栈的定义:

//定义
typedef struct Linknode{
	ElemType data;
	struct Linknode *next;
}Linknode, *LiStack; 

//等价于以下三句代码
struct Linknode{ //定义单链表的结点类型 
	ElemType data;//数据域 每个结点存放一个数据元素 
	struct Linknode *next;//指针域 指向单链表中下一个结点 
}; 
typedef struct Linknode Linknode;
typedef struct Linknode* LiStack; 

两种重命名后,声明时的区别:
Linknode * //强调这是一个结点
LiStack //强调这是一个单链表 
//Linknode是个结构体,LiStack是(结构体)指针。两种重命名的灵活选择,可以提升代码可读性。  

基本操作:

链栈的初始化(创):

不带头结点

//初始化(创)
//不带头节点 
bool InitLiStack(LiStack &S){
	if(S == NULL) return false;//非法参数
	S = NULL;
	return true; 
}

带头结点

//初始化(创)
//带头节点 
bool InitLiStack(LiStack &S){
	S = (Linknode *)malloc(sizeof(Linknode));
	if(S == NULL) return false;//内存不足,分配失败 
	S.next = NULL;
	return true; 
}

 链栈的判空:

//链栈的判空(带头结点)
bool LiStackEmpty(LiStack S){
	if(S.next == NULL) return true;
	else return false;
}

链栈的进栈操作(增):

//对应单链表对头结点的后插操作(头插法建立单链表)
bool Push(LiStack &S,ElemType x) {
	//判满 ? 
	Linknode *p = (Linknode *)malloc(sizeof(Linknode));//新元素
	if(p == NULL) return false;  //内存不足,分配失败
	p.data = x;
	p->next = S.next;
	S.next = p;//修改栈顶 
	return true;
}

链栈的出栈操作(删):

//对应单链表对头结点的后删操作
bool Pop(LiStack &S,ElemType &x) {
	if(S.next == NULL) return false;//栈空 无法出栈 报错
	x = S.next.data; 
	S.next == S.
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值