数据结构之队列详解(包含例题)
一、队列的概念
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
二、模拟实现顺序队列

我们可以用单链表模拟实现顺序队列。
队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部(对应单链表的尾插),而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素(对应单链表的头删)。
对应的接口
注意又提供一种避免使用二级指针的方法,创建一个结构体变量,里面存储结点,当我们想要改变结构体里面的值,我们就用一级指针即可。
typedef int QDataType;
typedef struct QueueNode
{//用单链表模拟实现队列struct QueueNode* next;QDataType data;
}QNode;//新的避免二级指针的结构体
typedef struct Queue
{QNode* head;QNode* tail;int sz;
}Que;void QueueInit(Que* pq);
void QueueDestory(Que* pq);
void QueuePush(Que* pq, QDataType x);
void QueeuPop(Que* pq);
QDataType QueueFront(Que* pq);
QDataType QueueBack(Que* pq);
bool QueueEmpty(Que* pq);
int QueueSize(Que* pq);
队列的初始化:
void QueueInit(Que* pq)
{assert(pq);pq->sz = 0;pq->head = pq->tail = NULL;
}
队列的销毁
注意free过后,也要指向空
void QueueDestroy(Que* pq)
{assert(pq);while (pq->sz > 0){QNode* cur = pq->head->next;free(pq->head);pq->head = cur;pq->sz--;}pq->tail = pq->head = NULL;
}
队列的插入数据
也就是单链表的尾插,同时也要注意当队列为空时的特殊情况。
void QueuePush(Que* pq,QDataType x)
{//类似于尾插assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror(malloc);exit(-1);}newnode->data = x;newnode->next = NULL;if (pq->head == NULL){pq->head = pq->tail = newnode;pq->sz++;}else{pq->sz++;pq->tail->next = newnode;pq->tail = newnode;}
}
队列的删除数据
也就是单链表的头删,同时也要注意只剩下一个结点删除后,尾结点指向空的情况
void QueeuPop(Que* pq)
{assert(pq);assert(pq->sz > 0);//头删//单独判断只剩下一个结点,头删后tail是野指针的情况if (pq->head->next == NULL){free(pq->head);pq->head = pq->tail = NULL;pq->sz--;}else{QNode* cur = pq->head;pq->head = pq->head->next;free(cur);pq->sz--;}}
返回队列头数据
QDataType QueueFront(Que* pq)
{assert(pq);//assert(pq->head);assert(!QueueEmpty(pq));return pq->head->data;
}
返回队列尾数据
QDataType QueueBack(Que* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}
判断队列是否为空
bool QueueEmpty(Que* pq)
{assert(pq);return pq->head == NULL;
}
返回队列的数据个数
int QueueSize(Que* pq)
{assert(pq);//assert(pq->head);return pq->sz;
}
三、模拟实现循环队列
622. 设计循环队列 - 力扣(LeetCode)
这实际上是把队列空间想象成一个环形空间,环形空间中的存储单元循环使用,用这种方法管理的队列也就称为循环队列。
注意本题结构较为复杂,必须要画图进行解决,这样就容易考虑到特殊情况,不容易出错。
本题用数组实现较为简单,如果用单链表实现,那么rear尾结点的前一个不好寻找。
那数组如何实现循环呢?
数组实现循环并不像单链表那样有一个next指针指向头结点,如果已经走向尾部,可以直接让头部的值等于尾部想要的值。
//如何用数组实现循环?
typedef struct {int* a;int front;int rear;int num;
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* cur = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//用k+1个数组空间,便于判断空和满的情况。cur->a = (int*)malloc(sizeof(int)*(k+1));cur->front = 0;cur->rear = 0;cur->num = k;return cur;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) {if(obj->front == obj->rear)return true;elsereturn false;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {//两种情况都要考虑到!if(obj->front-obj->rear == 1 || obj->rear-obj->front == obj->num)return true;elsereturn false;
}bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//先判断是否已经满if(myCircularQueueIsFull(obj) == true)return false;//假设rear在队列的尾部if(obj->rear == obj->num){obj->a[obj->rear] = value;obj->rear = 0;}else{obj->a[obj->rear] = value;obj->rear++;}//obj->a[obj->rear] = value;//obj->rear++;//obj->rear %= (obj->num+1);return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {//先判断是否已经空了if(myCircularQueueIsEmpty(obj) == true){return false;}//假设front在队列的尾部if(obj->front == obj->num)obj->front = 0;elseobj->front++;//++obj->front;//obj->front %= (obj->num+1);return true;
}int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj) == true)return -1;elsereturn obj->a[obj->front];
}int myCircularQueueRear(MyCircularQueue* obj) {//注意队尾的rear比数据提前一位数,所以是rear-1//但要考虑rear-1的情况if(myCircularQueueIsEmpty(obj) == true)return -1;if(obj->rear == 0){//需要再创建一个临时变量,不能改变rear的值int tmp = obj->num;return obj->a[tmp];}// else// return obj->a[(obj->rear+obj->num)%(obj->num+1)];return obj->a[obj->rear-1];
}void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);free(obj);
}
四、用队列实现栈
225. 用队列实现栈 - 力扣(LeetCode)
本题要求用两个队列实现栈,两个队列我们就可以互相倒数据,来满足题目对栈的需求!
思路:
入队列:
入不为空的队列
出队列:
利用队列的性质将前n-1个数据放入另一个空的队列中,删除剩下一个数据,这样就完成栈的pop操作!

代码:
typedef struct {Que q1;Que q2;
} MyStack;MyStack* myStackCreate() {MyStack* cur = (MyStack*)malloc(sizeof(MyStack));//不能忘记初始化QueueInit(&cur->q1);QueueInit(&cur->q2);return cur;
}void myStackPush(MyStack* obj, int x) {//push到不为空的的队列中if(!QueueEmpty(&obj->q1)){QueuePush(&obj->q1,x);}else{QueuePush(&obj->q2,x);}
}int myStackPop(MyStack* obj) {//先假设q1不为空,q2为空Que* empty = &obj->q1;Que* nonEmpty = &obj->q2;if(!QueueEmpty(&obj->q1)){//如果假设失败,相反empty = &obj->q2;nonEmpty = &obj->q1;}while(QueueSize(nonEmpty)>1){//开始用函数进行捯数据//从前往后的顺序是根据队列pop的顺序定的QueuePush(empty,QueueFront(nonEmpty));QueuePop(nonEmpty);}int top = QueueBack(nonEmpty);QueuePop(nonEmpty);return top;
}int myStackTop(MyStack* obj) {Que* empty = &obj->q1;Que* nonEmpty = &obj->q2;if(!QueueEmpty(&obj->q1)){//如果假设失败,相反empty = &obj->q2;nonEmpty = &obj->q1;}return QueueBack(nonEmpty);
}bool myStackEmpty(MyStack* obj) {//判断两个队列return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}void myStackFree(MyStack* obj) {//先对两个队列中的链表进行freeQueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj);
}
五、用栈实现队列
232. 用栈实现队列 - 力扣(LeetCode)
题目描述:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
思路:
本题与上一题用队列实现栈有所差别,可以直接区分push栈和pop栈,如果pop栈为空,就将push栈全部捯到pop栈!
代码:
typedef struct
{ST push;ST pop;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* cur = (MyQueue*)malloc(sizeof(MyQueue));SLInit(&cur->push);SLInit(&cur->pop);return cur;
}void myQueuePush(MyQueue* obj, int x) {STPush(&obj->push,x);
}int myQueuePop(MyQueue* obj) {int ret = myQueuePeek(obj);STPop(&obj->pop);return ret;
}int myQueuePeek(MyQueue* obj) {//出栈只能从后往前出//如果pop栈为空,就将push栈全部捯到pop栈!if(STEmpty(&obj->pop)){while(!STEmpty(&obj->push)){STPush(&obj->pop,STTop(&obj->push));STPop(&obj->push);}}int ret = STTop(&obj->pop);return ret;
}bool myQueueEmpty(MyQueue* obj) {//用函数求解return STEmpty(&obj->push) && STEmpty(&obj->pop);
}void myQueueFree(MyQueue* obj) {SLDestroy(&obj->pop);SLDestroy(&obj->push);free(obj);
}
相关文章:
数据结构之队列详解(包含例题)
一、队列的概念 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操…...
Prometheus的搭建与使用
一、安装Prometheus 官网下载地址:Download | Prometheus 解压:tar -zxvf prometheus-2.19.2.linux-amd64.tar.gz重命名: mv prometheus-2.19.2.linux-amd64 /home/prometheus进入对应目录: cd /home/prometheus查看配置文件&am…...
实战指南,SpringBoot + Mybatis 如何对接多数据源
系列文章目录 MyBatis缓存原理 Mybatis plugin 的使用及原理 MyBatisSpringboot 启动到SQL执行全流程 数据库操作不再困难,MyBatis动态Sql标签解析 从零开始,手把手教你搭建Spring Boot后台工程并说明 Spring框架与SpringBoot的关联与区别 Spring监听器…...
论文阅读——Imperceptible Adversarial Attack via Invertible Neural Networks
Imperceptible Adversarial Attack via Invertible Neural Networks 作者:Zihan Chen, Ziyue Wang, Junjie Huang*, Wentao Zhao, Xiao Liu, Dejian Guan 解决的问题:虽然视觉不可感知性是对抗性示例的理想特性,但传统的对抗性攻击仍然会产…...
List和ObservableCollection和ListBinding在MVVM模式下的对比
List和ObservableCollection和ListBinding在MVVM模式下的对比 List 当对List进行增删操作后,并不会对View进行通知。 //Employee public class Employee : INotifyPropertyChanged {public event PropertyChangedEventHandler? PropertyChanged;public string N…...
insightface安装过程中提示 Microsoft Visual C++ 14.0 or greater is required.
pip install insightface安装过程中提示 Microsoft Visual C 14.0 or greater is required.Get it with "Microsoft C Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/ 根据提示网站访问官网下载生成工具 打开软件后会自动更新环境&#…...
mongodb数据库
目录 一、数据库 二、文档 三、集合 四、元数据 五、MongoDB 数据类型 1、ObjectId 2、字符串 3、时间戳 4、日期 一、数据库 一个 mongodb 中可以建立多个数据库。 MongoDB 的默认数据库为"db",该数据库存储在 data 目录中。 MongoDB 的单…...
OpenCV-Python中的图像处理-图像特征
OpenCV-Python中的图像处理-图像特征 图像特征Harris角点检测亚像素级精度的角点检测Shi-Tomasi角点检测SIFT(Scale-Invariant Feature Transfrom)SURF(Speeded-Up Robust Features)FAST算法BRIEF(Binary Robust Independent Elementary Features)算法ORB (Oriented FAST and R…...
Ajax入门+aixos+HTTP协议
一.Ajax入门 概念:AJAX是浏览器与服务器进行数据通信的技术 axios使用: 引入axios.js使用axios函数:传入配置对象,再用.then回调函数接受结果,并做后续处理 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>01.axios使用…...
conda创建虚拟环境
创建虚拟环境是在计算机上设置一个独立的空间,用于安装和运行特定版本的软件和依赖项,以避免与系统其他部分的冲突。 创建虚拟环境: conda create --name myenv python3.8 这将创建一个名为myenv的虚拟环境,并安装Python 3.8版本。…...
Golang服务的请求调度
文章目录 1. 写在前面2. SheddingHandler的实现原理3. 相关方案的对比4. 小结 1. 写在前面 最近在看相关的Go服务的请求调度的时候,发现在gin中默认提供的中间件中,不含有请求调度相关的逻辑中间件,去github查看了一些服务框架,发…...
Jenkins的流水线启动jar后未执行问题处理
现象 在流水线里配置了启动脚本例如,nohup java -jar xxx.jar >nohup.out 2>&1 & 但是在服务器发现服务并未启动,且nohup日志里没输出日志,这样的原因是jenkins在执行完脚本后,就退出了这个进程。 在启动脚本执行jar命令的上一步加入以下…...
智慧工地平台工地人员管理系统 可视化大数据智能云平台源码
智慧工地概述: 智慧工地管理平台是以物联网、移动互联网技术为基础,充分应用大数据、人工智能、移动通讯、云计算等信息技术,利用前端信息采通过人机交互、感知、决策、执行和反馈等,实现对工程项目內人员、车辆、安全、设备、材…...
外包干了2个月测试,技术退步明显...
先说一下自己的情况,大专生,18年通过校招进入湖南某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…...
神经网络基础-神经网络补充概念-19-向量化实现的解释
概念 向量化是一种优化技术,通过使用数组操作代替显式的循环,可以大大提高代码的性能和效率。在机器学习和数据分析领域,向量化是一种常见的实践,它允许你在处理大量数据时更快地进行计算。 一般操作 数组操作:向量…...
四层和七层负载均衡的区别
一、四层负载均衡 四层就是ISO参考模型中的第四层。四层负载均衡器也称为四层交换机,它主要时通过分析IP层和TCP/UDP层的流量实现的基于“IP端口”的负载均衡。常见的基于四层的负载均衡器有LVS、F5等。 以常见的TCP应用为例,负载均衡器在接收到第一个来…...
Scala 如何调试隐式转换--隐式转换代码的显示展示
方法1 在需要隐式转换的地方,把需要的参数显示的写出。 略方法2,查看编译代码 在terminal中 利用 scalac -Xprint:typer xxx.scala方法打印添加了隐式值的代码示例。 对于复杂的工程来说,直接跑到terminal执行 scalac -Xprint:typer xxx.…...
Rust交叉编译简述 —— Arm
使用系统:WSL2 —— Kali(Microsoft Store) 命令列表 rustup target list # 当前官方支持的构建目标架构列表 rustup target add aarch64-unknown-linux-gnu # 添加目标架构sudo apt-get install gcc-13-aarch64-linux-gnu gcc-13-aarch64-linux-gnu # 下载目标工具…...
算法与数据结构(二十三)动态规划设计:最长递增子序列
注:此文只在个人总结 labuladong 动态规划框架,仅限于学习交流,版权归原作者所有; 也许有读者看了前文 动态规划详解,学会了动态规划的套路:找到了问题的「状态」,明确了 dp 数组/函数的含义&a…...
相机的位姿在地固坐标系ECEF和ENU坐标系的转换
在地球科学和导航领域,通常使用地心地固坐标系(ECEF,Earth-Centered, Earth-Fixed)和东北天坐标系(ENU,East-North-Up)来描述地球上的位置和姿态。如下图所示: 地心地固坐标ecef和…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
