数据结构之队列详解(包含例题)

news2024/11/26 3:11:06

一、队列的概念

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(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;
    else
        return false;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    //两种情况都要考虑到!
    if(obj->front-obj->rear == 1 || obj->rear-obj->front == obj->num)
        return true;
    else
        return 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;
    else
        obj->front++;
    //++obj->front;
    //obj->front %= (obj->num+1);
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj) == true)
        return -1;
    else
        return 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) {
    //先对两个队列中的链表进行free
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}

五、用栈实现队列

232. 用栈实现队列 - 力扣(LeetCode)

题目描述:

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

思路:

本题与上一题用队列实现栈有所差别,可以直接区分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);
}

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

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

相关文章

l2a股接口从哪几方面测评?(l2行情接口)

股票数据接口是一种用于获取、传输和处理股票市场相关数据的软件接口。l2a股接口提供了一种连接股票市场数据源和数据使用者之间的通道,允许开发者通过编程方式获取股票行情数据、交易数据和相关信息等。 股票数据接口主要有两种类型:实时行情数据接口和…

SPI协议个人记录

SPI协议 SPI(Serial Peripheral Interface)是一种同步串行接口技术,由Motorola公司推出。SPI总线系统是一种同步串行外设接口,允许MCU与各种外围设备以串行方式进行通信和数据交换。外围设备包括FLASHRAM、A/D转换器、网络控制器…

时序预测-Informer简介

文章目录 Informer介绍1. Transformer存在的问题2. Informer研究背景3. Informer 整体架构3.1 ProbSparse Self-attention3.2 Self-attention Distilling3.3 Generative Style Decoder 4. Informer的实验性能5. 相关资料 Informer介绍 1. Transformer存在的问题 Informer实质…

SysML V1.2 Ports and Flows

概述 本章介绍了流端口,它们允许在块和部件之间传输物品流,以及标准端口,它们允许在块和部件上调用服务。端口是块或部件与其环境之间的交互点,通过连接器与其他端口相连。指定系统元素上的这些端口的主要动机是允许设计具有明确…

【TI毫米波雷达笔记】IWR6843AOP的CCS工程模板创建(DSS)

【TI毫米波雷达笔记】IWR6843AOP的CCS工程模板创建(DSS) 如果还不会配置MSS 则看我的文章: blog.csdn.net/weixin_53403301/article/details/132274755大体上与MSS创建也差不多 SDK我用的3.5版本 DSS工程模板: download.csdn.…

HTML和JavaScript实现一个简单的计算器

使用HTML和JavaScript实现一个简单的计算器。 一、绘制键盘 <!DOCTYPE html> <html> <head><title>Simple Calculator</title><style>.calculator {display: grid;grid-template-columns: repeat(4, 1fr);grid-gap: 5px;padding: 10px;}.…

产品进行逻辑梳理的三个重点

我们在进行产品方案设计时&#xff0c;需要进行逻辑梳理&#xff0c;这样才能保障产品方案的严谨性&#xff0c;降低后期返工几率。如果我们在接到需求时&#xff0c;直接开始画原型&#xff0c;没有经过逻辑梳理&#xff0c;往往容易造成产品方案纰漏丛生&#xff0c;直接影响…

NFTScan | 08.07~08.13 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。周期&#xff1a;2023.08.07~ 2023.08.13 NFT Hot News 01/Magic Eden 已上线 BRC-20 小数铭文与买卖 8 月 7 日&#xff0c;NFT 市场 Magic Eden 发推称&#xff0c;BRC-20 小数铭文与买卖现已上线&…

CentOS8安装Git

错误1. 执行yum命令报错 【错误&#xff1a;Invalid configuration value: failovermethodpriority in /etc/yum.repos.d/CentOS-epel.repo; 配置&#xff1a;ID 为 "failovermethod" 的 OptionBinding 不存在】 1.cd /etc/yum.repos.d 2.vim CentOS-epel.repo //…

计算机竞赛 opencv 图像识别 指纹识别 - python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于机器视觉的指纹识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&#xff0c;适…

Python实现SSA智能麻雀搜索算法优化BP神经网络回归模型(BP神经网络回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 麻雀搜索算法(Sparrow Search Algorithm, SSA)是一种新型的群智能优化算法&#xff0c;在2020年提出&a…

布隆过滤器原理及应用

使用场景 适用于数据命中不高、 数据相对固定、 实时性低&#xff08;通常是数据集较大&#xff09; 的应用场景。比如&#xff1a; 解决缓存穿透&#xff1b;爬虫时记录已爬取的网页&#xff1b;记录黑名单&#xff1b; 原理 数据结构是一个bit数组&#xff0c;布隆过滤器…

Rx.NET in Action 中文介绍 前言及序言

Rx 处理器目录 (Catalog of Rx operators) 目标可选方式Rx 处理器(Operator)创建 Observable Creating Observables直接创建 By explicit logicCreate Defer根据范围创建 By specificationRangeRepeatGenerateTimerInterval Return使用预设 Predefined primitivesThrow …

【vue】alert弹窗太死板?试试这种方法(附代码)

alert(response.data.message); 新方法&#xff1a; this.$message.error(请检查您输入的的用户名和密码&#xff01;);

等保案例 2

用户简介 青海省司法厅是贯彻执行国际司法行政的方针、政策&#xff0c;拟定青海市司法行政工作的政策、法规的重要组织机构。青海省司法厅根据国家部署及业务需要先后简历了司法专网及行政办公网&#xff0c;目前两套网络之间完全物理隔离。但青海省司法厅现有网络设备单一&a…

学会这个小技巧,让你的Jenkins更好用

♥ 前 言 在使用 Jenkins 时&#xff0c;我们经常遇到这样的需求&#xff1a;在 Jenkins 构建的时候拉取指定分支的代码或者指定 tag 的代码&#xff0c;而 Jenkins 默认没有带这样的参数化选择功能&#xff0c;我们可以通过 Git Parameter 插件来实现。 一、准备&#xff…

公文管理系统SSM+Activiti文档文件日志java jsp源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 公文管理系统SSMActiviti 系统有1权限&#xff1a;管…

达摩院FunASR实时语音听写服务软件包发布

7月初&#xff0c;FunASR社区发布了离线文件转写软件包&#xff0c;可以高精度、高效率、高并发的支持长音频离线文件转写&#xff0c;吸引了众开发者参与体验。应开发者需求&#xff0c;FunASR社区再次推出实时语音听写服务软件包&#xff0c;支持实时地进行语音转文字&#x…

如何进行网络活动监控

组织的 IT 基础架构中的每个网络设备上都发生了大量活动&#xff0c;例如数据包传输、来自网络协议的消息、设备状态事件等。网络活动成为在检测到问题时识别网络瓶颈的面包屑&#xff0c;因此即使是最微小的网络活动也应受到监控&#xff0c;因为它直接影响整体网络性能、运行…

Python web实战之Django的AJAX支持详解

关键词&#xff1a;Web开发、Django、AJAX、前端交互、动态网页 今天和大家分享Django的AJAX支持。AJAX可实现在网页上动态加载内容、无刷新更新数据的需求。 1. AJAX简介 AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;是一种在网页上实现异步通信的技术。通过…