当前位置: 首页 > news >正文

第三章 栈和队列【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的分类&#xff1…...

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…...

python打卡day49

知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

浅谈不同二分算法的查找情况

二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况&#xf…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...

提升移动端网页调试效率:WebDebugX 与常见工具组合实践

在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...