第三章 栈和队列【24王道数据结构笔记】
1.栈
1.1 栈的基本概念
- 只允许在一端(栈顶top)进行插入或删除操作的受限的线性表。
- 后进先出(Last In First Out)LIFO。或者说先进后出FILO。
进栈顺序:a1 > a2 > a3 > a4 > a5
出栈顺序:a5 > a4 > a3 > a2 > a1
1.2 栈的基本操作
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。
1.2.1 栈的顺序存储实现

【顺序栈的定义】
#define MaxSize 10 //定义栈中元素的最大个数typedef struct{ElemType data[MaxSize]; //静态数组存放栈中元素int top; //栈顶元素
}SqStack;void testStack(){SqStack S; //声明一个顺序栈(分配空间)//连续的存储空间大小为 MaxSize*sizeof(ElemType)
}
【顺序栈的初始化】
#define MaxSize 10
typedef struct{ ElemType data[MaxSize]; int top;
}SqStack;// 初始化栈顶为-1,栈顶指针指向栈顶
void InitStack(SqStack &S){ S.top = -1; //初始化栈顶指针
}// 判断栈是否为空
bool StackEmpty(SqStack S){ if(S.top == -1) return true; else return false;
}// 初始化栈顶为0,栈顶指针指向栈顶的下一个空位
void InitStack(SqStack &S){ S.top = 0; //初始化栈顶指针
}// 判断栈是否为空
bool StackEmpty(SqStack S){ if(S.top == 0) return true; else return false;
}
【顺序栈的入栈出栈】
初始化为-1时
// 新元素进栈
bool Push(SqStack &S, ElemType x){ if(S.top == MaxSize - 1) // 判断栈是否已满 return false; S.data[++S.top] = x; return true;
}// 出栈
bool Pop(SqStack &x, ElemType &x){ if(S.top == -1) // 判断栈是否为空 return false; x = S.data[S.top--]; return true;
}初始化为0时
// 新元素进栈
bool Push(SqStack &S, ElemType x){ if(S.top == MaxSize) // 判断栈是否已满 return false; S.data[S.top++] = x; return true;
}// 出栈
bool Pop(SqStack &x, ElemType &x){ if(S.top == 0) // 判断栈是否为空 return false; x = S.data[--S.top]; return true;
}
【读取栈顶元素】
// 读栈顶元素
初始化为-1时
bool GetTop(SqStack S, ElemType &x){ if(S.top == -1) 先判空,非空读取才有意义 return false; x = S.data[S.top]; return true;
}初始化为-1时
bool GetTop(SqStack S, ElemType &x){ if(S.top == 0) return false; x = S.data[S.top-1]; return true;
}
【读取栈的长度】
// 获取当前栈长
当初始化为-1
int GetSize(SqStack S){ return S.top + 1;
}当初始化为0
int GetSize(SqStack S){ return S.top;
}
共享栈(两个栈共享同一片空间)】
- 共享栈--特殊的顺序栈
- 将栈底设计在共享空间的两端,栈顶向中间靠拢
#define MaxSize 10 //定义栈中元素的最大个数typedef struct{ElemType data[MaxSize]; //静态数组存放栈中元素int top0; //0号栈栈顶指针int top1; //1号栈栈顶指针
}ShStack;//初始化栈
void InitSqStack(ShStack &S){S.top0 = -1; //初始化栈顶指针S.top1 = MaxSize;
}
1.2.2 栈的链式存储
【链栈的定义】
- 定义:采用链式存储的栈称为链栈。
- 优点:链栈的优点是便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。
- 特点:进栈和出栈都只能在栈顶一端进行(链头作为栈顶)
链表的头部作为栈顶,意味着:
- 1. 在实现数据"入栈"操作时,需要将数据从链表的头部插入;
- 2. 在实现数据"出栈"操作时,需要删除链表头部的首元节点;
因此,链栈实际上就是一个只能采用头插法插入或删除数据的链表;
栈的链式存储结构可描述为:
【链栈的定义】
typedef struct Linknode{ ElemType data; //数据域 Linknode *next; //指针域
}Linknode,*LiStack;void testStack(){ LiStack L; //声明一个链栈
}
【链栈的初始化】
typedef struct Linknode{ ElemType data; Linknode *next;
}Linknode,*LiStack;// 初始化栈
bool InitStack(LiStack &L){ // 生成虚拟头节点,并将其next指针置空L = (Linknode *)malloc(sizeof(Linknode)); if(L == NULL) return false; L->next = NULL; return true;
}// 判断栈是否为空
bool isEmpty(LiStack &L){ if(L->next == NULL) return true; else return false;
}
【入栈出栈】
// 新元素入栈
bool pushStack(LiStack &L,ElemType x){ Linknode *s = (Linknode *)malloc(sizeof(Linknode)); if(s == NULL) return false; s->data = x; // 头插法 s->next = L->next; L->next = s; return true;
}// 出栈
bool popStack(LiStack &L, int &x){ // 栈空不能出栈 if(L->next == NULL) return false; Linknode *s = L->next; x = s->data; L->next = s->next;free(s);s = NULL; return true;
}
2. 队列
2.1 队列的基本概念
- 只允许在表的一端(队尾)插入,表的另一端(队头)进行删除操作的受限的线性表。
- 特点:先进先出(先入队的元素先出队)、FIFO(First In First Out),后入后出LILO。
2.2 队列的基本操作
InitQueue(&Q):初始化队列,构造一个空队列Q。
QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回false。
EnQueue(&Qx):入队,若队列Q未满,则将x加入使之成为新的队尾。
DeQueue(&Q&x):出队,若队列Q非空,则删除队头元素,并用x返回。
GetHead(Q&x):读队头元素,若队列Q非空则用x返回队头元素。
ClearQueue(&Q):销毁队列,并释放队列Q占用的内存空间。
【队列的顺序存储实现 】
队头指针:指向队头元素
队尾指针:指向队尾元素或者队尾的下一个位置
【顺序队列的定义】
#define MaxSize 10; //定义队列中元素的最大个数typedef struct{ ElemType data[MaxSize]; //用静态数组存放队列元素 int front, rear; //队头指针和队尾指针
}SqQueue;void test{ SqQueue Q; //声明一个队列
}
【顺序队列的初始化】
#define MaxSize 10;typedef struct{ ElemType data[MaxSize]; int front, rear;
}SqQueue;// 初始化队列
void InitQueue(SqQueue &Q){ // 初始化时,队头、队尾指针指向0 // 队尾指针指向的是即将插入数据的数组下标 // 队头指针指向的是队头元素的数组下标Q.rear = Q.front = 0;
}// 判断队列是否为空
bool QueueEmpty(SqQueue Q){ if(Q.rear == Q.front) 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;
}
- 循环队列不能直接使用Q.rear == Q.front作为判空的条件,因为当队列已满时也符合该条件,会与判空发生冲突!
解决方法一:牺牲一个单元来区分队空和队满,即将(Q.rear+1)%MaxSize == Q.front作为判断队列是否已满的条件。(主流方法)
解决方法二:设置 size 变量记录队列长度。
#define MaxSize 10; typedef struct{ ElemType data[MaxSize]; int front, rear; int size;
}SqQueue;// 初始化队列
void InitQueue(SqQueue &Q){ Q.rear = Q.front = 0; Q.size = 0;
}// 判断队列是否为空
bool QueueEmpty(SqQueue 0){ if(Q.size == 0) return true; else return false;
}// 新元素入队
bool EnQueue(SqQueue &Q, ElemType x){ if(Q.size == MaxSize) return false;Q.size++; Q.data[Q.rear] = x; Q.rear = (Q.rear+1)%MaxSize; return true;
}// 出队
bool DeQueue(SqQueue &Q, ElemType &x){ if(Q.size == 0) return false;Q.size--;x = Q.data[Q.front]; Q.front = (Q.front+1)%MaxSize; return true;
}
解决方法三:设置 tag 变量记录队列最近的操作。(tag=0
:最近进行的是删除操作;tag=1
:最近进行的是插入操作)
#define MaxSize 10; typedef struct{ ElemType data[MaxSize]; int front, rear; int tag;
}SqQueue;// 初始化队列
void InitQueue(SqQueue &Q){ Q.rear = Q.front = 0; Q.tag = 0;
}// 判断队列是否为空,只有tag==0即初始化或者出队后才可能为空
bool QueueEmpty(SqQueue 0){ if(Q.front == Q.rear && Q.tag == 0) return true; else return false;
}// 新元素入队 判断队列是否满,只有tag==1即入队后才可能满
bool EnQueue(SqQueue &Q, ElemType x){if(Q.rear == Q.front && tag == 1) return false; Q.data[Q.rear] = x; Q.rear = (Q.rear+1)%MaxSize; Q.tag = 1; return true;
}// 出队
bool DeQueue(SqQueue &Q, ElemType &x){if(Q.rear == Q.front && tag == 0) return false; x = Q.data[Q.front];Q.front = (Q.front+1)%MaxSize; Q.tag = 0; return true;
}
【获得队头元素】
// 获取队头元素并存入x
bool GetHead(SqQueue &Q, ElemType &x){if(Q.rear == Q.front) return false;x = Q.data[Q.front]; return true;
}
队列的链式存储实现
【链队列的定义】
// 链式队列结点
typedef struct LinkNode{ ElemType data; struct LinkNode *next;
}// 链式队列
typedef struct{ // 头指针和尾指针 LinkNode *front, *rear;
}LinkQueue;
【 链队列的初始化(带头结点)】
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.front == Q.rear) return true; else return false;
}
【入队出队(带头结点)】
// 新元素入队
void EnQueue(LinkQueue &Q, ElemType x){ // 不存在满的情况LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode)); s->data = x; s->next = NULL; 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; // 如果p是最后一个结点,此时Q.rear已经要被删除了,则将队尾指针也指向队首指针 if(Q.rear == p) Q.rear = Q.front; free(p);p = NULL; return true;
}
【不带头结点的链队列操作】
typedef struct LinkNode{ ElemType data; struct LinkNode *next;
}LinkNode;typedef struct{ LinkNode *front, *rear;
}LinkQueue;// 初始化队列
void InitQueue(LinkQueue &Q){ // 不带头结点的链队列初始化,头指针和尾指针都指向NULLQ.front = NULL; Q.rear = NULL;
}// 判断队列是否为空
bool IsEmpty(LinkQueue Q){ if(Q.front == NULL) return true; else return false;
}// 新元素入队
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 == NULL)return false;LinkNode *s = Q.front;x = s->data;if(Q.front == Q.rear){Q.front = Q.rear = NULL;}else{Q.front = Q.front->next;}free(s);return true;
}
双端队列
双端队列定义
- 双端队列是允许从两端插入、两端删除的线性表。
- 如果只使用其中一端的插入、删除操作,则等同于栈。
- 输入受限的双端队列:允许一端插入,两端删除的线性表。
- 输出受限的双端队列:允许两端插入,一端删除的线性表。
双端队列考点:判断输出序列的合法化
- 例:数据元素输入序列为 1,2,3,4,判断 4! = 24 个输出序列的合法性
输入受限的双端队列:只有 4213 和 4231 不合法
输出受限的双端队列:只有 4132 和 4231 不合法
相关文章:

第三章 栈和队列【24王道数据结构笔记】
1.栈 1.1 栈的基本概念 只允许在一端(栈顶top)进行插入或删除操作的受限的线性表。后进先出(Last In First Out)LIFO。或者说先进后出FILO。 进栈顺序:a1 > a2 > a3 > a4 > a5出栈顺序:a5 > a4 > a3 > a2 …...

保姆级教程之SABO-VMD-CNN-SVM的分类诊断,特征可视化
今天出一期基于SABO-VMD-CNN-SVM的分类诊断。 依旧是采用经典的西储大学轴承数据。基本流程如下: 首先是以最小包络熵为适应度函数,采用SABO优化VMD的两个参数。其次对每种状态的数据进行特征向量的求取,并为每组数据打上标签。然后将数据送入…...

跳跃游戏(贪心思想)
题解 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 输入样例 示例 1…...

【JavaSE语法】类和对象(二)
六、 封装 6.1 封装的概念 面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。 封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互…...

【SA8295P 源码分析 (三)】121 - MAX9295A 加串器芯片手册分析 及初始化参数分析
【SA8295P 源码分析】121 - MAX9295A 加串器芯片手册分析 及初始化参数分析 一、MAX9295A 芯片特性1.1 GPIO 引脚说明1.2 功能模块框图1.3 时序分析1.3.1 GMSL2 Lock Time:25 ms1.3.2 视频初始化延时:1.1ms + 17000 x t(PCLK)1.3.3 High-Speed Data Transmission in Bursts1.…...

Maya 2024 for Mac(3D建模软件)
Maya 2024是一款三维计算机图形软件,具有强大的建模、动画、渲染、特效等功能,广泛应用于影视、游戏、广告等行业。以下是Maya 2024软件的主要功能介绍: 建模:Maya 2024具有强大的建模工具,包括多边形建模、曲面建模、…...

9. 深度学习——GAN
机器学习面试题汇总与解析——GAN 本章讲解知识点 从 GAN 讲起本专栏适合于Python已经入门的学生或人士,有一定的编程基础。本专栏适合于算法工程师、机器学习、图像处理求职的学生或人士。本专栏针对面试题答案进行了优化,尽量做到好记、言简意赅。这才是一份面试题总结的正…...

BeanUtils中的copyProperties方法使用
一、Beanutils中的copyProperties是我们在日常开发中常用的一个方法。 作用: 将a实体类中的属性赋值到b实体类中相对于的字段上 1.我们前端传参的时候我们后端通常会用vo实体类来接收,但是更新数据库的时候需要用do去操作 2.我们将vo的属性copy到do中可…...

hivesql连续日期统计最大逾期/未逾期案例
1、虚表(测试表和数据) create test_table as select a.cust_no, a.r_date, a.yqts from ( select 123 as cust_no, 20231101 as r_date, 0 as yqts union all select 123 as cust_no, 20231102 as r_date, 1 as yqts union all select 123 as cust_no, 20231103 as r_d…...

基于STM32的无线通信系统设计与实现
【引言】 随着物联网的迅速发展,无线通信技术逐渐成为现代通信领域的关键技术之一。STM32作为一款广受欢迎的微控制器,具有丰富的外设资源和强大的计算能力,在无线通信系统设计中具有广泛的应用。本文将介绍如何基于STM32实现一个简单的无线通…...

kubernetes--pod详解
目录 一、pod简介: 1. Pod基础概念: 2. Kubrenetes集群中Pod的两种使用方式: 3. pod资源中包含的容器: 4. pause容器的两个核心功能: 5. Kubernetes中使用pause容器概念的用意: 二、pod的分类࿱…...

WPF提供了哪些不同类型的画刷
在WPF中,画刷(Brush)用于填充图形对象(如形状、控件的背景和前景)的颜色和样式。WPF提供了几种不同类型的画刷: SolidColorBrush:这是最简单的画刷,它提供了一个单一的、固定的颜色。…...

STM32与ZigBee技术在智能家居无线通信中的应用研究
一、引言 智能家居系统是利用物联网技术将家庭各种设备进行互联互通,实现智能化控制和管理的系统。在智能家居系统中,无线通信技术起着至关重要的作用,而STM32微控制器和ZigBee技术则是实现智能家居无线通信的关键技术。本文将对STM32与ZigB…...

【Apache Doris】审计日志插件 | 快速体验
【Apache Doris】审计日志插件 | 快速体验 一、 环境信息1.1 硬件信息1.2 软件信息 二、 审计日志插件介绍三、 快速 体验3.1 AuditLoader 配置3.1.1 下载 Audit Loader 插件3.1.2 解压安装包3.1.3 修改 plugin.conf 3.2 创建库表3.3 初始化3.4 验证 一、 环境信息 1.1 硬件信…...

Web安全:Vulfocus 靶场搭建.(漏洞集成平台)
Web安全:Vulfocus 靶场搭建.(漏洞集成平台) Vulfocus 是一个包含了多种漏洞靶场的镜像。每个靶场都有具体的漏洞环境和攻击点。Vulfocus 的靶场包括了 Web 安全漏洞、系统安全漏洞、网络安全漏洞、密码学漏洞等多种类型。通关这个靶场我们可以…...

Go ZIP压缩文件读写操作
创建zip文件 golang提供了archive/zip包来处理zip压缩文件,下面通过一个简单的示例来展示golang如何创建zip压缩文件: func createZip(filename string) {// 缓存压缩文件内容buf : new(bytes.Buffer)// 创建zipwriter : zip.NewWriter(buf)defer writ…...

全堆栈图像生成器专为Multiverse后端Bootcamp设计,结合了React、Firebase和Hugging Face API
目录 1 Full Stack Image Generator 1.1 Features 1.2 Technologies Used 1.3 Setup Instructions 1.4 Contributing 1.5 Acknowledgements Full Stack Image Generator This is a full-stack image generator built as a part of the Multiverse Backend Bootcam…...

【C#学习】button:只显示图片
第一步:设置按钮背景图片,并且图片随按钮大小变化 第二步:设置按钮使之只显示图片 button1.FlatStyle FlatStyle.Flat;//stylebutton1.ForeColor Color.Transparent;//前景button1.BackColor Color.Transparent;//去背景button1.FlatAppe…...

我招基础初级运维实习生的面试题
不考虑对错,只要能答上来60%可面试。 如果出现的“不知道”、“不清楚”、“没用过”太多,就pass。 Linux发行版 说一些知道的Linux系统 centos\ubuntu\redhat\ubuntu\debian\kylin LInux基础命令 在Linux上如何查看IP?说一个用过的。 i…...

vue实现浏览器关闭或刷新弹窗提示(beforeunload/unload)
vue实现浏览器关闭或刷新弹窗提示 一、推荐代码二、错误情况说明1.在beforeunload事件里面加alert2.在一个没有焦点的 iframe 或 frame 浏览器会阻止 beforeunload 弹窗3.无法触发destroyed/beforedestroyed/deactivated4.能触发beforeRouteEnter,但不能触发beforeR…...

Zookeeper学习笔记(1)—— 基础知识
Zookeeper概述 Zookeeper 是一个开源的分布式的,为分布式框架提供协调服务的 Apache 项目 工作机制 Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受…...

mp4视频批量截取!!!
mp4视频批量截取!!! 问题:如果我们想截取一个mp4视频中的多个片段,一个一个截会很麻烦! 可以将想要截取的开始时间和结束时间保存到 excel表 中,进行批量截取。 1、对一个视频,记…...

jQuery - AJAX get() 和 post() 方法
jQuery - AJAX get() 和 post() 方法 jQuery get() 和 post() 方法用于通过 HTTP GET 或 POST 请求从服务器请求数据。 HTTP 请求:GET vs POST 两种在客户端和服务器端进行请求-响应的常用方法是:GET 和 POST。 GET - 从指定的资源请求数据 POST - 向…...

设计模式(4)-行为型模式
行为型模式 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间…...

JavaScript概述
一、JavaScript简介: JavaScript是互联网上流行的脚本语言,可用于HTML和web,可广泛应用于服务器、PC、笔记本、平板电脑和智能手机等设备。 JavaScript是一种轻量级的编程语言,可插入HTML页面的编程代码,插入HTML页面后…...

Solidity案例详解(四)投票智能合约
该合约为原创合约,功能要求如下 在⼀定时间能进⾏投票超过时间投票截⽌,并投赞同票超过50%则为通过。 使⽤safeMath库,使⽤Owner 第三⽅库拥有参与投票权的⽤户在创建合约时确定Voter 结构 要有时间戳、投票是否同意等;struct 结构…...

Linux系统编程——进程中vfork函数
函数原型 pid_t vfork(void);//pid_t是无符号整型 所需头文件 #include <sys/types.h> #include <unistd.h> 功能 vfork() 函数和 fork() 函数一样都是在已有的进程中创建一个新的进程,但它们创建的子进程是有区别的。 返回值 成功子进程中返回 …...

敏感数据是什么?包含哪些?如何保障安全?
最近看到不少小伙伴在问,敏感数据是什么?包含哪些?如何保障安全?这里我们小编就给大家一一解答一下,仅供参考哦! 敏感数据是什么? 敏感数据,是指泄漏后可能会给社会或个人带来严重危…...

Leadshop开源商城小程序源码 – 支持公众号H5
Leadshop是一款出色的开源电商系统,具备轻量级、高性能的特点,并提供持续更新和迭代服务。该系统采用前后端分离架构(uniappyii2.0),以实现最佳用户体验为目标。 前端部分采用了uni-app、ES6、Vue、Vuex、Vue Router、…...

Scala---方法与函数
一、Scala方法的定义 有参方法&无参方法 def fun (a: Int , b: Int) : Unit {println(ab) } fun(1,1)def fun1 (a: Int , b: Int) ab println(fun1(1,2)) 注意点: 方法定义语法 用def来定义可以定义传入的参数,要指定传入参数的类型方法可以写返…...