【数据结构】队列、环形队列

article/2025/9/28 0:57:18


目录

1.队列的概念及结构

 2.队列的实现

3.队列的相关实现函数与源代码

3.1初始化队列

3.2 队尾入队列 

3.3 队头出队列 

3.4获取队列头部元素 

3.5 获取队列队尾元素 

3.6 获取队列中有效元素个数 

3.7检测队列是否为空

3.8销毁队列 

4.环形队列

4.1环形队列概念

4.2实现环形队列

4.2.1.实现环形队列的前期准备:相关结构体

4.2.2.创建环形队列,设置队列长度为 k 

4.2.3. 实现循环队列判空函数和判满函数

4.2.5.插入和删除元素 

4.2.6.从队首和队尾获取元素

4.3环形队列完整代码

在最后


1.队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)

入队列:进行插入操作的一端称为队尾。

出队列:进行删除操作的一端称为队头。


2.队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数 组头上出数据,效率会比较低。


3.队列的相关实现函数与源代码

对其使用的结构体的定义:

typedef  int QDataType;//用单链表实现队列// 链式结构:表示队列 
typedef struct QListNode
{struct QListNode* next;QDataType data;
}QNode;// 队列的结构 
typedef struct Queue
{QNode* front;QNode* rear;
}Queue;

通过队头队尾front、rear这两个指针来访问队列,执行队列的基本操作。


3.1初始化队列

// 初始化队列
void QueueInit(Queue* q)
{assert(q);q->front =q->rear= NULL;
}

3.2 队尾入队列 

分两种情况队列为空和队列不为空。

在创建新节点的时候直接把新节点的next初始化为空,后续链接就不用重新把尾结点置为空

QNode* AddNode(QDataType data)
{QNode* p = (QNode*)malloc(sizeof(QNode));if (p == NULL){perror("malloc error\n");exit(-1);}p->data = data;p->next = NULL;//直接把新节点的next初始化为空,后续链接就不用重新把尾结点置为空return p;
}
//从队尾添加数据
// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{assert(q);//情况1.如果是空队列if (q->front == NULL){q->front = q->rear = AddNode(data);}//情况2.队列不为空else{QNode* tail = AddNode(data);q->rear->next = tail;q->rear = tail;}
}

3.3 队头出队列 

删除掉队头的数据

请注意如果队列中只有一个元素时,需要进行判断。

释放这个节点之后把指向队列的头尾指针都置为空,否则只是单纯的q->front=q->front->next,q->rear不变的话,就会造成q->rear指向一个已经释放的节点的情况,会造成野指针的问题。

// 队头出队列 
void QueuePop(Queue* q)
{assert(q);assert(!QueueEmpty(q));//如果删除的是最后一个if (q->front->next == NULL){free(q->front);q->front = q->rear = NULL;}QNode* head = q->front;q->front = q->front->next;free(head);head = NULL;}

3.4获取队列头部元素 

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->front->data;
}

3.5 获取队列队尾元素 

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->rear->data;
}

3.6 获取队列中有效元素个数 

遍历整个队列计算长度。

// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{assert(q);assert(!QueueEmpty(q));int i = 0;QNode* head = q->front;while (head){i++;head = head->next;}return i;
}

也可以直接在一开始定义的时候直接把结构体改为:

// 队列的结构 
typedef struct Queue
{QNode* front;QNode* rear;int size;
}Queue;

在之后的入队列出队列的时候都进行相应的++或者--


3.7检测队列是否为空

如果为空返回非零结果,如果非空返回0 

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q)
{assert(q);return q->front == NULL;
}

3.8销毁队列 

记得销毁队列时,把队列的节点全部释放之后,记得在最后把指向队列的前后指针置为空。

// 销毁队列 
void QueueDestroy(Queue* q)
{assert(q);QNode* head = q->front;QNode* next = NULL;while (head){next = head->next;free(head);head=next;}q->front = q->rear = NULL;//销毁队列之后记得把头尾指针置为空
}


4.环形队列

4.1环形队列概念

环形队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

环形队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

 环形队列可以使用数组实现,也可以使用循环链表实现。如果使用数组实现,注意数组下标访问越界问题。

以下用数组实现环形队列:


4.2实现环形队列

以力扣622.设计循环队列为例:

622. 设计循环队列 - 力扣(LeetCode)https://leetcode.cn/problems/design-circular-queue/在这个题目中我们一共要实现有关环形队列的七个函数:

MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。


4.2.1.实现环形队列的前期准备:相关结构体

在这个结构体中需要定义指向环形队列起始位置的指针、头尾下标以及申请的实际空间的大小。

typedef int QueueDataType;typedef struct { QueueDataType* a;//指向队列的指针QueueDataType front;//头尾下标QueueDataType tail;int size;//申请的实际空间大小
} MyCircularQueue;

4.2.2.创建环形队列,设置队列长度为 k 


4.2.3. 实现循环队列判空函数和判满函数


4.2.5.插入和删除元素 


4.2.6.从队首和队尾获取元素


4.3环形队列完整代码

typedef int QueueDataType;typedef struct { QueueDataType* a;//指向队列的指针QueueDataType front;//头尾下标QueueDataType tail;int size;//申请的实际空间大小
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* point=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//QueueDataType*point->a=(QueueDataType*)malloc(sizeof(QueueDataType)*(k+1));//多申请一个空余空间方便判空和满point->front=point->tail=0;//头尾下标都为0point->size=k+1;return point;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->tail==obj->front;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {return (obj->tail+1)%obj->size==obj->front;}bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{//先判断是否非满
if(myCircularQueueIsFull(obj))
{return false;
}//向tail插入数据然后tail++
obj->a[obj->tail]=value;
//小心tail越界问题
obj->tail++;
obj->tail=obj->tail%obj->size;
return true;}bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return false;}obj->front=(obj->front+1)%obj->size;return true;}int myCircularQueueFront(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj)){return -1;}return obj->a[obj->front];}int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}//注意obj->tail始终在队列元素的下一个坐标,所以打印最后一个坐标要--return obj->a[(obj->tail-1+obj->size)%obj->size];}void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);free(obj);obj=NULL;
}

在最后

       好久不见,这里是媛仔~马上开学了,最近不知道为什么就开始摆烂了,好久也没有更新博客了T-T,把这篇博客当中重新开始吧!!加油加油!!

       希望这篇博客对你能够有所帮助,也希望大家可以和媛仔多多交流,谢谢大家!(最后的这个表情包是媛仔自己做的哦,祝你天天开心 ^-^


http://chatgpt.dhexx.cn/article/ymnQ6fQk.shtml

相关文章

java环形队列_数组实现环形队列Java

用数组实现环形队列的特点是高效。 能快速判断队列是否 满/空; 能快速存取数据。 因为简单高效,所以甚至在硬件中都实现了环形队列。 环形队列广泛应用于网络数据的收发,和不同应用间数据交换(内核和应用程序大量交换数据,从硬件接…

环形队列初步探讨

文章目录 前言一、环形队列二、环形队列基本操作二、示例总结 前言 最近使用队列的时候,在实现大数据整体平移的时候还是用了内存copy虽然暂时达到性能要求,但是总感觉很笨重,最后用环形队列重构了部分代码,效果还行。 一、环形队…

环形队列

介绍 环形队列是队列的一种特殊情况,也是基于队列的实现,队列是动态的集合,而环形队列则是固定长度的,当队列满时,则从队首删除元素。其原理基本和队列一致,都是实现先进先出的策略。 实现 先定义数据&…

C语言,环形队列

什么是环形队列? 环形缓冲区是一个非常典型的数据结构,这种数据结构符合生产者,消费者模型,可以理解它是一个水坑,生产者不断的往里面灌水,消费者就不断的从里面取出水。 那就可能会有人问,既然…

数据结构(10)---队列之环形队列

环形队列 文章目录 环形队列什么是环形队列循环队列的实现第一种实现第二种实现 什么是环形队列 环形队列也是队列的一种数据结构, 也是在队头出队, 队尾入队; 只是环形队列的大小是确定的, 不能进行一个长度的增加, 当你把一个环形队列创建好之后, 它能存放的元素个数是确定的…

数据结构--环形队列的介绍与实现

数据结构--环形队列实现 一、环形队列实现原理环形队列的几个判断条件 二、代码实现1.环形队列类(CircleQueue)2.环形队列类测试类3.程序运行结果4.完整代码 环形队列可以用数组实现,也可以使用循环链表实现.在使用数组实现循环队列的时候&am…

【数据结构(C语言描述)】环形队列

目录 一、基础知识二、数组实现环队2.1 初始化2.2 判断环队是否为空2.3 判断环队是否为满2.4 入队2.5 出队2.6 取队头元素2.7 取队尾元素2.8 销毁环队 三、链表实现环队3.1 初始化3.2 判断环队是否为空3.3 判断环队是否为满3.4 入队3.5 出队3.6 取队头元素3.7 取队尾元素3.8 销…

环形队列原理,全网最通俗易懂

队列是什么 队列是一种很常见的数据结构,满足先进先出的方式,如果我们设定队列的最大长度,那就意味着进队列和出队列的元素的数量实则满足一种动态平衡。 如果我们把首次添加入队列的元素作为一个一维坐标的原点,那么随着队列中…

Mysql 死锁和死锁的解决方案

最近在研究Mysql底层原理,研究到了死锁,感觉挺有意思,在这里和大家分享一下 前置知识:需要了解锁的种类,如表锁、行锁;行锁又分为记录锁、间隙锁、临键锁等等;什么情况下会加表锁,什…

mysql死锁演示

背景: 线上日志突然爆了有数据库死锁的日志。 通过以下语句查询数据库死锁的日志 SHOW ENGINE INNODB STATUS 通过 日志分析,看到了两条update语句并且是里面有子查询。还有两个表的更新顺序问题。 解决方案是:加了分布式锁,…

记录一次mysql死锁

一,死锁发现 项目中有一个接口包含更新操作1,后面发现更新失败,通过查看应用程序日志,发现发生了死锁 sql 1 如下 1.最初版本根据id为条件,更新(plan_start_time 二级索引) update tt_task …

深入MySQL死锁场景

总结死锁需满足以下条件: 2个或者2个以上的并发事务操作并发事务之间存在锁冲突锁冲突关系成环形 GAP锁和Insert的隐式锁,最容易导致死锁,以下分析从这俩典型场景开始。 1. 表结构 建立以下表作为场景验证,id为主键&#xff0…

mysql死锁查询语句

mysql 死锁:如何解决mysql死锁 可直接在mysql命令行执行:showengineinnodbstatus\G;查看造成死锁的sql语句,分析索引情况,然后优化sql然后showprocesslist;另外可以打开慢查询日志,linux下打开需在my.cnf的[mysqld]里面加上以下内…

MySQL死锁排查步骤

系列文章目录 第一章:sql_mode模式 第二章:optimize table、analyze table、alter table、gh-ost 第三章:InnoDB MVCC原理 第四章:sql语句执行过程 第五章:Percona Toolkit工具简介 第六章:MySQL索引 第七…

MySql死锁过程

死锁一般怎么导致呢, 抛开一堆概念, 我就把死锁当成死结。 就是你代码获取锁的顺序问题。 MySql的死锁和我们正常代码也一样, 都是互通的, 当你修改一个表的行数据的时候, 就需要对那一行数据进行加锁。 所以很容易想…

中秋遇到mysql死锁怎么办

文章目录 前言一、什么是死锁二、死锁的产生条件三、死锁示例四、死锁的分析和查看1.查看最近1个死锁信息2.查看正在运行中的事务信息3.查看加锁信息 五、死锁的内部处理方案1.死锁探测机制2.锁等待超时机制 六、手动释放锁1.表级锁手动释放2.行级锁手动释放 七、死锁的优化策略…

mysql 死锁分析

一、 什么是死锁 死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等的进程称为死锁进程.二、 死锁产生的四个必要条件 1.互斥条件:指进…

MySQL死锁分析

背景知识 MySQL数据库InnoDB引擎的行级锁在使用时是在索引记录上加锁的。 行级锁从占有模式上分为: 排他锁:独占行数据,如某事务获取了该行记录的排他锁,其他事务在获取该记录的排他锁和共享锁时需等待;共享锁&…

故障分析 | MySQL死锁案例分析

作者:杨奇龙 网名“北在南方”,资深 DBA,主要负责数据库架构设计和运维平台开发工作,擅长数据库性能调优、故障诊断。 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转…

MySQL死锁

参考博客: https://blog.csdn.net/sinat_41653656/article/details/109629094 Mysql 锁类型和加锁分析 MySQL有三种锁的级别:页级、表级、行级。 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大&#xff…