数据结构详细笔记——栈与队列

news2024/11/25 13:54:16

文章目录

  • 栈的三要素
    • 逻辑结构(定义)
    • 数据的运算(基本操作)
    • 存储结构(物理结构)
      • 顺序栈(顺序存储)
      • 链栈(链式存储)
  • 队列的三要素
    • 逻辑结构(定义)
    • 数据的运算(基本操作)
    • 存储结构(物理结构)
      • 顺序队列(顺序存储)
      • 链式队列(链式存储)
  • 队列的变种
  • 栈在括号匹配中的应用
  • 栈在表达式求值中的应用
    • 中缀表达式 ------>后缀表达式
    • 后缀表达式的计算
    • 中缀表达式 ------>前缀表达式
    • 前缀表达式的计算
    • 用栈实现中缀表达式的计算


栈的三要素

逻辑结构(定义)

栈是只允许在一端进行插入或删除操作的线性表

特点:后进先出(LIFO)

数据的运算(基本操作)

InitStack(&S)
初始化栈:构造一个空栈S,分配内存空间

DestroyStack(&S)
销毁栈:销毁并释放栈S所占用的内存空间

Push(&S,x)
进栈:若栈S未满,则将x加入使之成为新栈顶

Pop(&S,&x)
出栈:若栈非空,则弹出栈顶元素,并用x返回

GetTop(S,&x)
读栈顶元素:若栈S非空,则用x返回栈顶元素

StackEmpty(S)
判断一个栈S是否为空,若S为空,则返回true,否则返回false

栈的常考题型
已知进栈顺序,问有哪些合法的出栈顺序?
出栈元素不同排列的个数为卡特兰数

存储结构(物理结构)

顺序栈(顺序存储)

顺序栈的定义

#define MaxSize 10
typedef struct{
	ELemType data[MaxSize];   // 静态数组存放栈中元素
	int top;                  // 栈顶指针
}SqStack;

初始化栈

void InitStack(SqStack &S){
	S.top = 0;
}

判空

bool StackEmpty(SqStack S){
	if(S.top == -1)
		return true;
	else
		return false;
]

进栈操作

bool Push(SqStack &S,ElemType x){
	if(S.top == MaxSize - 1)
		renturn false;
	S.top = S.top + 1;   // 指针先加1
	S.data[S.top] = x;   // 新元素入栈
	return true;
}

出栈操作

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

读栈顶元素

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

共享栈

#define MaxSize 10
typedef struct{
	ElemType data[MaxSize];
	int top0;      // 0号栈栈顶指针
	int top1;      // 1号栈栈顶指针
} ShStack;

// 初始化栈
void InitStack(ShStack &S){
	S.top0 = -1;
	S.top1 = MaxSize;
}

栈满的条件: top0 + 1 = top1

链栈(链式存储)

链栈的定义
其操作相当于头插法建立单链表(只从表头进行增加删除操作)

typedef struct LinkNode{
	ELemType data;   // 数据域
	struct LinkNode *next;     // 指针域
}*LinkStack;

队列的三要素

逻辑结构(定义)

队列是只允许在一端进行插入,在另一端删除的线性表

特点:先进先出(FIFO)

数据的运算(基本操作)

InitQueue(&Q)
初始化队列:构造一个空队列Q

DestroyQueue(&Q)
销毁队列:销毁并释队列Q所占用的内存空间

EnQueue(&Q,x)
入队:若队列Q未满,则将x加入使之成为新的队尾

DeQueue(&Q,&x)
出队:若队列非空,删除队头元素,并用x返回

GetHead(Q,&x)
读队头元素:若队列Q非空,则用x返回队头元素

QueueEmpty(Q)
判断一个队列Q是否为空,若Q为空,则返回true,否则返回false

存储结构(物理结构)

顺序队列(顺序存储)

队列的顺序实现

#define MaxSize 10
typedef struct{
	ElemType data[MaxSize];
	int front,rear;
} SqQueue;

初始化队列

void InitQueue(SqQueue &Q){
	Q.rear = Q.front = 0;
}

判断队列是否为空

bool QueueEmpty(SqQueue Q){
	if(Q.rear == Qfront)
		return true;
	else
		return false;
}

入队

bool EnQueue(SqQueue &Q,ElemType x){
	if((Q.rear + 1) % MaxSize == Q.front)
		return false;    //队满则报错
	Q.data[Q.rear] = x;
	Q.rear = (Q.rear + 1) % MaxSize;  //队尾指针加一取模
	return true;
} 

出队

bool DeQueue(SqQueue &Q,ElemType &x){
	if(Q.rear == Q.front)
		return false;   // 队空则报错
	x = Q.data[Q.front];
	Q.front = (Q.front + 1) % MaxSize;
	return true;
}

获取队头元素的值,用x返回

bool GetHead(SqQueue Q,ElemType &x){
	if(Q.rear == Q.front)
		return false;
	x = Q.data[Q.front];
	return true;
}

队列元素的个数:
(rear - front + MaxSzie)% MaxSize

链式队列(链式存储)

队列的链式实现

typedef struct LinkNode{    // 链式队列结点
	ElemType data;  
	struct LinkNode *next;
}LinkNode;

typedef struct{             // 链式队列
	LinkNode *front,*rear;  // 队列的队头和队尾指针
}LinkQueue;

初始化(带头结点)

void InitQueue(LinkQueue &Q){
	// 初始化 front、rear 都指向头结点
	Q.front = Q.rear = (LinkNode *) malloc(sizeof(LinkNode));
	Q.front->next = NULL;
}

队列是否为空

bool IsEmpty(LinkQueue Q){
	if(Q.rear == Qfront)
		return true;
	else
		return false;
}

新元素入队(带头结点)

void EnQueue(LinkNode &Q,ElemType x){
	LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = null;
	Q.rear->next = s;
	Q.rear = s;
}

在这里插入图片描述

入队(不带头结点)

void EnQueue(LinkQueue &Q,ElemType x){
	LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;
	if(Q.front == NULL){   // 在空队列中插入第一个元素
		Q.front = s;       // 修改队头队尾的指针
		Q.rear = s;
	} else{
		Q.rear->next = s;
		Q.rear = s;
	}
}

出队(带头结点)

bool DeQueue(LinkQueue &Q,ElemType &x){
	if(Q.front == Q.rear)
		return false;    // 空队
	LinkNode *p = Q.front->next;
	x = p.data;
	Q.front->next = p->next;
	if(Q.rear == p)   // 此次是最后一个结点出队
		Q.rear = Q.front;
	free(p);          // 释放结点空间
	return true;
}

出队(不带头结点)

bool DeQueue(LinkQueue &Q,ElemType &x){
	if(Q.front == NULL)
		return false;
	LinkNode *p = Q.front;
	x = p->data;
	Q.front = p->next;
	if(Q.rear = p)[
		Q.front = NULL;
		Q.rear = NULL;
	}
	free(p);
	return true;
}

队列的变种

双端队列:允许从两端插入、两端删除的队列

输入受限的双端队列:允许从两端删除、从一端插入的队列

输出受限的双端队列:允许从两端插入、从一端删除的队列

考点:对输出序列的合法性的判断

栈在括号匹配中的应用

括号匹配流程图

代码实现

#define MaxSize 10
typedef struct{
	char data[MaxSize];
	int top;
}SqStack;

// 初始化栈
void InitStack(SqStack &S)

// 判断栈是否为空
bool StackEmpty(SqStack S)

// 新元素入栈
bool Push(SqStack &S,char x)

// 栈顶元素出栈,用x返回
bool Pop(SqStack &S,char &x)

bool bracketCheck(char str[],int length){
	SqStack S;
	InitStack(S);  // 初始化
	for(int i = 0; i < length; i++){
		if(str[i] == '(' || str[i] == '[' || str[i] == '{'){
			Push(S, str[i]);  // 扫描到左括号,入栈
		} else {
			if(StackEmpty(S))  // 扫描到右括号,并且当前栈空
				return false;  // 匹配失败
			char topElem;
			Pop(S, topElem);   // 栈顶元素出栈
			if(str[i] == ')' && topElem != '(')
				return false;
			if(str[i] == ']' && topElem != '[')
				return false;
			if(str[i] == '}' && topElem != '{')
				return false;
		}
	}
	return StackEmpty(S);   // 检索完全部括号后,栈空说明匹配成功
} 

栈在表达式求值中的应用

三种算术表达式:
1、中缀表达式:运算符在两个操作数中间 —— a+b
2、后缀表达式(逆波兰表达式):运算符在两个操作数后面 —— ab+
3、前缀表达式(波兰表达式):运算符在两个操作数前面 —— +ab

中缀表达式 ------>后缀表达式

手算

1、确定中缀表达式中各个运算符的运算顺序
2、选择下一个运算符,按照【 左操作符 右操作符 运算符 】的方式组合成一个新的操作数
3、如果还有运算符没被处理,就继续2
注意:为了保证手算和机算结果相同,采用“左优先”原则:只有左边的运算符能先运算,就优先算左边(可保证运算顺序唯一)

机算

初始化一个栈,用于保存暂时还不能确定运算顺序的运算符
从左到右处理各个元素,直到末尾,可能遇到三种情况:
1、遇到操作数:直接加入后缀表达式
2、遇到界限符:遇到 “ ( ” 直接入栈,遇到 “ ) ” 则依次弹出栈内运算符并加入后缀表达式,直到弹出 “ ( ” 为止。注意:“ ( ” 不加入后缀表达式
3、遇到运算符:依次弹出栈中优先级高于或者等于当前运算符的所有运算符,并加入后缀表达式,若碰到 “ ( ” 或栈空则停止。之后再把当前的运算符入栈
4、处理完所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式

后缀表达式的计算

1、从左往右扫描下一个元素,直到处理完所有的元素
2、若扫描到操作数则压入栈,并回到1;否则执行3
3、若扫描到运算符,则弹出两个栈顶元素,执行相应运算(先出栈的是右操作数),运算结果压回栈顶,回到1
4、若表达式合法。则最后栈中只会留下一个元素,就是最终结果

中缀表达式 ------>前缀表达式

1、确定中缀表达式中各个运算符的运算顺序
2、选择下一个运算符,按照【 运算符 左操作符 右操作符 】的方式组合成一个新的操作数
3、如果还有运算符没被处理,就继续2
注意:为了保证手算和机算结果相同,采用“右优先”原则:只有右边的运算符能先运算,就优先算右边(可保证运算顺序唯一)

前缀表达式的计算

1、从右往左扫描下一个元素,直到处理完所有的元素
2、若扫描到操作数则压入栈,并回到1;否则执行3
3、若扫描到运算符,则弹出两个栈顶元素,执行相应运算(先出栈的是左操作数),运算结果压回栈顶,回到1
4、若表达式合法。则最后栈中只会留下一个元素,就是最终结果

用栈实现中缀表达式的计算

中缀表达式 ------>后缀表达式后缀表达式的计算 的结合

*初始化两个栈:操作数栈 和 运算符栈
若扫描到操作数,压入操作数栈
若扫描到运算符或者界限符,则按照“中缀转后缀”相同的逻辑压入运算符栈
每当弹出一个运算符时,就需要在弹出两个操作数栈的栈顶元素并执行相应的运算,运算结果再压回操作数栈中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1101444.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实现更低功耗R5F51406BDNE、R5F51406ADFK、R5F51406ADFL、R5F51406AGFN搭载RXv2内核的32位微控制器

一、简介 RX140产品群是RX100系列中处理性能最强、功耗最低的微控制器。可以广泛应用于家用电器、工业控制和楼宇自动化等领域。RX140采用RXv2内核&#xff0c;工作频率最高48MHz&#xff0c;处理性能是32MHz运行的RX130的近两倍。此外&#xff0c;它在运行时的电路为56μA/MH…

03、RocketMQ环境搭建 -- linux

目录 RocketMQ环境搭建linux部署RocketMQ启动NameServer启动Broker关闭nameserver:关闭broker 监控平台 RocketMQ环境搭建 linux部署RocketMQ http://rocketmq.apache.org/release_notes/release-notes-4.4.0/ 下载包 解压失败 安装 zip、unzip应用 yum install zip unzip …

华为再度发声!坚决打好坚实的算力底座,为实现全智能新突破打好基础!

原创 | 文 BFT机器人 10月13号&#xff0c;在2023年中国移动全球合作伙伴大会上&#xff0c;华为轮值董事长胡厚崑发表讲话&#xff0c;在会议上胡厚崑发表“共建智算底座&#xff1a;坚持架构创新&#xff0c;汇聚生态力量&#xff0c;使能‘百模千态’大模型”观点&#xff…

Mac OS m1 下安装Gradle5.1

1. 下载、解压 1.1 下载地址 https://gradle.org 往下翻 选择 5.1 或者选择 任何 你想要的版本 ,点击 binary-only 即可下载 . 1.2 解压到指定目录 2. 配置环境变量 2.1 编辑环境文件 vi ~/.bash_profile #GRADLE相关配置 GRADLE_HOME/Users/zxj/Documents/devSoft/grad…

医院陪诊小程序:改善患者体验的技术创新

在数字化时代&#xff0c;医疗领域也迎来了革命性的变革。医院陪诊小程序作为这场变革的一部分&#xff0c;为患者和家属提供了前所未有的便捷和支持。这篇文章将探讨医院陪诊小程序的技术实现&#xff0c;以及如何使用代码来创建一个基本的医院陪诊小程序。 什么是医院陪诊小…

Archive Team: The Twitter Stream Grab

该集合不再更新&#xff0c;应被视为静态数据集。 从一般 Twitter 流中抓取的 JSON 的简单集合&#xff0c;用于研究、历史、测试和记忆的目的。这是“Spritzer”版本&#xff0c;最轻、最浅的 Twitter 抓取。不幸的是&#xff0c;我们目前无法访问流的洒水器或花园软管版本。 …

封装的方法固定的参数,特殊环境下需要多带参数

组件封装的时候某些方法回传出去某些参数&#xff0c;但是特殊条件下需要将其他参数也一并带入方法中使用 比如图片中的方法就可以实现不影响自带的参数&#xff0c;也不影响我们需要多带的参数

QQ大文件如何传输?分享最简单的方法!

QQ作为一个常用的交流工具&#xff0c;我们常常需要通过QQ发送一些大文件&#xff0c;但是文件太大在传输的过程中可能会导致无法发送或被退回。这个时候就需要借助一些文件压缩工具&#xff0c;先把文件瘦身再进行发送&#xff0c;下面是常用的三种方法。 一、QQ邮箱 直接使用…

composer selfupdate或composer self-update不管用解决办法

报错信息&#xff1a;这里可以看见我进行了composer self-update不管用&#xff0c;版本还是停留在1.10.27 解决办法&#xff1a; composer self-update --2

负债99.5万美元的【飞天兆业】申请1125万美元纳斯达克IPO上市

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于北京的Pheton Holdings Ltd&#xff08;飞天兆业&#xff09;近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纳斯达克IPO上市&#xff0c;股票代码…

运维的进阶:用它解决90%以上问题

#01 IT运维环境 发生哪些变化&#xff1f; — 在数字化转型的浪潮之下&#xff0c;一方面&#xff0c;企业IT环境变得多样化&#xff0c;另一方面&#xff0c;用户对业务稳定性的严格要求使IT运维团队需要更快地做出响应&#xff0c;所以运维将会是未来IT管理的重要一环。 …

QGIS提取两条线元素的交点

**选择图层 Vector -> Analysis Tools**

视频推拉流/直播点播平台EasyDSS分享的链接提示“无信号”,该如何解决?

视频直播点播平台EasyDSS可支持用户自行上传视频文件&#xff0c;也可将上传的点播文件作为虚拟直播进行播放。平台能支持多屏播放&#xff0c;可兼容Windows、Android、iOS、Mac等操作系统&#xff0c;还能支持CDN转推&#xff0c;具备较强的可拓展性与灵活性。 为给用户提供更…

双十一电视盒子什么品牌好?网友票选目前最强的电视盒子

上个月我发起了一次目前最强的电视盒子的投票活动&#xff0c;截止到现在共有超两千网友投票&#xff0c;入选的电视盒子品牌超十个。双十一想买电视盒子不知道电视盒子什么品牌好&#xff0c;可以看看网友们最爱的五大电视盒子品牌是哪些。 一、泰捷WEBOX新品WE40S电视盒子 推…

服务器数据恢复-linux+raid+VMwave ESX数据恢复案例

服务器数据恢复环境&#xff1a; 一台某品牌x3950 X6型号服务器&#xff0c;linux操作系统&#xff0c;12块硬盘组建了一组raid阵列&#xff0c;上层运行VMwave ESX虚拟化平台。 服务器故障&#xff1a; 在服务器运行过程中&#xff0c;该raid阵列中有硬盘掉线&#xff0c;linu…

饲料化肥经营商城小程序的作用是什么

我国农牧业规模非常高&#xff0c;各种农作物和养殖物种类多&#xff0c;市场呈现大好趋势&#xff0c;随着近些年科学生产养殖逐渐深入到底层&#xff0c;专业的肥料及饲料是不少从业者需要的&#xff0c;无论城市还是农村都有不少经销店。 但在实际经营中&#xff0c;经营商…

探索数字安全的卓越之选 - Digicert证书

在数字时代&#xff0c;数据安全和隐私保护变得尤为重要。无论是个人网站、电子商务平台还是大型企业&#xff0c;保护用户数据和建立信任都是至关重要的任务。在这个领域&#xff0c;Digicert是一个备受推崇的品牌&#xff0c;提供了卓越的数字证书解决方案&#xff0c;以确保…

Learning Deep Convolutional Networks for Demosaicing

Abstract 本文对应用卷积神经网络&#xff08;CNN&#xff09;解决去马赛克问题进行了全面的研究。该论文提出了两种 CNN 模型&#xff0c;它们可以学习马赛克样本和具有完整信息的原始图像块之间的端到端映射。在使用拜耳滤色器阵列 (CFA) 的情况下&#xff0c;对流行基准的评…

Shopee买家通系统:注册虾皮买家号需要些什么资料?

Shopee买家通系统可以全自动批量注册虾皮买家号&#xff0c;在运行自动注册时可以自动输入手机号、自动处理遇到的图形验证、自动接收短信、自动输入密码进行注册&#xff0c;注册成功后还能自动输入邮箱及接收邮箱验证进行验证绑定&#xff0c;全自动化操作更方便及节约时间。…

uniapp-vue3-微信小程序-标签选择器wo-tag

采用uniapp-vue3实现, 是一款支持高度自定义的标签选择器组件&#xff0c;支持H5、微信小程序&#xff08;其他小程序未测试过&#xff0c;可自行尝试&#xff09; 可到插件市场下载尝试&#xff1a; https://ext.dcloud.net.cn/plugin?id14960 使用示例 <template>&…