【数据结构】队列知识点总结--定义;基本操作;队列的顺序实现;链式存储;双端队列;循环队列

 欢迎各位看官^_^

目录

1.队列的定义

2.队列的基本操作

2.1初始化队列

2.2判断队列是否为空

2.3判断队列是否已满

2.4入队

2.5出队

2.6完整代码 

3.队列的顺序实现

4.队列的链式存储

5.双端队列

6.循环队列


1.队列的定义

        队列(Queue)是一种先进先出(First In First Out,FIFO)的线性数据结构,它只允许在队尾添加元素,在队头删除元素,不支持随机访问。队列常用的操作有入队(enqueue)、出队(dequeue)、队列长度(size)、队列是否为空(empty)等。队列可以用来实现很多算法,如广度优先搜索算法(BFS)和消息传递等。

2.队列的基本操作

2.1初始化队列

        可以使用数组或链表来实现队列。对于数组,我们可以定义一个数组和两个指针(front和rear)来表示队列。对于链表,我们可以创建一个链表,并定义头节点指针和尾节点指针。队列是一种线性数据结构,可以用数组或链表来实现。

以下是用数组实现队列的C语言代码示例:

#include <stdio.h>#define MAX_SIZE 100int queue[MAX_SIZE];
int front = 0, rear = -1;void enqueue(int data) {if (rear == MAX_SIZE - 1) {printf("Queue overflow\n");} else {rear++;queue[rear] = data;}
}int dequeue() {if (front > rear) {printf("Queue underflow\n");return -1;} else {int data = queue[front];front++;return data;}
}int main() {enqueue(10);enqueue(20);enqueue(30);printf("%d ", dequeue());printf("%d ", dequeue());printf("%d ", dequeue());printf("%d ", dequeue());return 0;
}

        上述代码中,`queue`为数组,`front`和`rear`分别表示队列的前后指针,初始化为`0`和`-1`。`enqueue`函数用于向队列中添加元素,先判断队列是否已满,若未满则将数据存入队列尾部。`dequeue`函数用于弹出队列头部元素,先判断队列是否为空,若非空则返回队列头部元素并将`front`指针后移一位。在`main`函数中,先将元素10、20、30添加到队列中,然后依次弹出队列头部元素并输出。

2.2判断队列是否为空

如果队列为空,则front和rear指向同一个位置。

// 判断队列是否为空
int is_empty() {return front == rear;
}

2.3判断队列是否已满

如果队列已满,则rear指向的下一个位置就是front(因为它是循环队列)。

// 判断队列是否已满
int is_full() {return (rear + 1) % MAX_SIZE == front;
}

2.4入队

当队列不满时,我们将元素插入队列的rear位置,并将rear指针后移。

// 入队
void enqueue(int data) {if (is_full()) {printf("Queue is full.\n");return;}queue[rear] = data;rear = (rear + 1) % MAX_SIZE;
}

2.5出队

当队列不为空时,我们将front指向的元素从队列中删除,并将front指针后移。

// 出队
int dequeue() {if (is_empty()) {printf("Queue is empty.\n");return -1;}int data = queue[front];front = (front + 1) % MAX_SIZE;return data;
}

2.6完整代码 

#include <stdio.h>
#define MAX_SIZE 10      // 定义队列的最大容量为10int queue[MAX_SIZE];     // 定义数组队列
int front = 0, rear = 0; // front指向队首,rear指向队尾的下一个位置// 判断队列是否为空
int is_empty() {return front == rear;
}// 判断队列是否已满
int is_full() {return (rear + 1) % MAX_SIZE == front;
}// 入队
void enqueue(int data) {if (is_full()) {printf("Queue is full.\n");return;}queue[rear] = data;rear = (rear + 1) % MAX_SIZE;
}// 出队
int dequeue() {if (is_empty()) {printf("Queue is empty.\n");return -1;}int data = queue[front];front = (front + 1) % MAX_SIZE;return data;
}int main() {enqueue(1);enqueue(2);enqueue(3);printf("%d\n", dequeue());printf("%d\n", dequeue());enqueue(4);printf("%d\n", dequeue());printf("%d\n", dequeue());return 0;
}

        注意:这是一个循环队列,在计算rear的位置时需要使用取模运算。这是因为数组的最后一个位置后面没有下一个位置,我们需要将rear回到数组的开头位置。 

3.队列的顺序实现

C语言队列的顺序实现可以使用数组来实现。实现思路如下:

  1. 定义一个数组和队列头尾指针。
  2. 队列头指针指向队列的第一个元素,队列尾指针指向队列的最后一个元素。
  3. 入队操作时,先判断队列是否已满,如果已满则提示队列已满,否则将元素加入到队列尾部,并更新队列尾指针。
  4. 出队操作时,先判断队列是否为空,如果为空则提示队列为空,否则将队列头部的元素出队,并更新队列头指针。
  5. 获取队列头元素时,先判断队列是否为空,如果为空则提示队列为空,否则返回队列头的元素。

以下是C语言队列的顺序实现示例代码:

#include <stdio.h>
#define MAX_SIZE 100// 定义队列结构体
typedef struct {int data[MAX_SIZE];  // 存储队列的数组int front;  // 队列头指针int rear;   // 队列尾指针
} Queue;// 初始化队列
void initQueue(Queue *q) {q->front = q->rear = 0;
}// 入队
void enqueue(Queue *q, int x) {if ((q->rear + 1) % MAX_SIZE == q->front) {printf("Queue is full.\n");} else {q->data[q->rear] = x;q->rear = (q->rear + 1) % MAX_SIZE;}
}// 出队
void dequeue(Queue *q) {if (q->front == q->rear) {printf("Queue is empty.\n");} else {q->front = (q->front + 1) % MAX_SIZE;}
}// 获取队列头元素
int front(Queue *q) {if (q->front == q->rear) {printf("Queue is empty.\n");return -1;} else {return q->data[q->front];}
}// 判断队列是否为空
int isEmpty(Queue *q) {return q->front == q->rear;
}int main() {Queue q;initQueue(&q);// 入队enqueue(&q, 1);enqueue(&q, 2);enqueue(&q, 3);// 获取队列头元素printf("Front of queue: %d\n", front(&q));// 出队dequeue(&q);// 获取队列头元素printf("Front of queue: %d\n", front(&q));return 0;
}

 

4.队列的链式存储

        队列和链表的关系:队列和链表是两种不同的数据结构,但是在实现队列时可以使用链表来表示。队列是一种先进先出(First In First Out,FIFO)的数据结构,可以理解为是一条通道,从一端(队尾)加入数据,从另一端(队头)取出数据。而链表是一种动态数据结构,由节点之间的指针连接而成。每个节点包含一个数据元素和一个指向下一个节点的指针。在使用链表实现队列时,可以将链表的头作为队列的队头,将链表的尾作为队列的队尾,使用链表的头插法或尾插法对队列进行入队操作,使用链表的尾删除或头删除对队列进行出队操作。因此,可以说队列和链表有一定的关系,但二者仍然是不同的数据结构。 

        队列的链式存储是使用链表来实现队列的存储结构。队列的链式存储结构可以分为单向链表和双向链表两种。

        单向链表的存储结构是每个节点包含一个数据元素和一个指向下一个节点的指针。队列的头指针指向链表的头节点,队列的尾指针指向链表的尾节点。入队操作将元素添加到尾节点之后,出队操作则删除头节点。

        双向链表的存储结构是每个节点包含一个数据元素、一个指向前一个节点的指针和一个指向下一个节点的指针。队列的头指针指向链表头部,队列的尾指针指向链表尾部。入队操作将元素添加到尾节点之后,出队操作则删除头节点。

        链式存储相比于顺序存储的优势在于可以更灵活地插入和删除元素,但是在访问元素时需要通过指针遍历链表,效率较低。

        链式存储结构的队列通常包含一个头结点和一个尾结点,其中头结点指向队列的头部,尾结点指向队列的尾部。每个结点都包含一个数据域和一个指针域,指针域指向下一个结点。

以下是C语言实现队列的链式存储的示例代码:

#include <stdio.h>
#include <stdlib.h>// 队列结点定义
typedef struct queue_node{int data;                   // 数据域struct queue_node *next;    // 指针域
} queue_node;// 队列定义
typedef struct {queue_node *front;          // 队列头指针queue_node *rear;           // 队列尾指针
} queue;// 初始化队列
void init_queue(queue *q)
{// 分配头结点q->front = q->rear = (queue_node *)malloc(sizeof(queue_node));if (!q->front) {printf("Memory allocation failed.\n");exit(-1);}q->front->next = NULL;
}// 判断队列是否为空
int is_empty(queue *q)
{return q->front == q->rear;
}// 入队
void enqueue(queue *q, int data)
{queue_node *new_node = (queue_node *)malloc(sizeof(queue_node));if (!new_node) {printf("Memory allocation failed.\n");exit(-1);}new_node->data = data;new_node->next = NULL;q->rear->next = new_node;q->rear = new_node;
}// 出队
int dequeue(queue *q)
{if (is_empty(q)) {printf("Queue is empty.\n");exit(-1);}queue_node *p = q->front->next;int data = p->data;q->front->next = p->next;if (q->rear == p) {q->rear = q->front;}free(p);return data;
}// 输出队列中元素
void print_queue(queue *q)
{queue_node *p = q->front->next;while (p) {printf("%d ", p->data);p = p->next;}printf("\n");
}int main()
{queue q;init_queue(&q);for (int i = 1; i <= 5; i++) {enqueue(&q, i);}print_queue(&q);dequeue(&q);print_queue(&q);return 0;
}

5.双端队列

        双端队列(deque,全名double-ended queue)是一种具有队列和栈的性质的数据结构,即两端都可以进行插入和删除操作。

        双端队列有两个端点:一个是“前端”(front),可以进行“出队”操作;另一个是“后端”(rear),可以进行“入队”操作。因此,双端队列支持的操作包括入队、出队、队头入队、队尾入队、队头出队、队尾出队等。

        与单端队列相比,双端队列的优势在于可以自由地从两端添加或删除元素,更加灵活、方便地实现某些算法和数据结构。例如,在实现图遍历算法中,使用双端队列可以使得遍历的顺序更加合理,减少搜索的时间和空间复杂度。

        另外,双端队列支持一些其他的操作,如获取队列长度、获取队头/尾元素等。

以下是C语言实现双端队列的代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>// 双端队列节点结构体
typedef struct DequeNode {int val;struct DequeNode* next;struct DequeNode* prev;
} DequeNode;// 双端队列结构体
typedef struct Deque {DequeNode* front; // 队头指针DequeNode* rear; // 队尾指针int size; // 队列元素个数
} Deque;// 初始化双端队列
void initDeque(Deque* deque) {deque->front = NULL;deque->rear = NULL;deque->size = 0;
}// 判断双端队列是否为空
bool isEmptyDeque(Deque* deque) {return deque->size == 0;
}// 获取双端队列的长度
int sizeDeque(Deque* deque) {return deque->size;
}// 获取双端队列队头元素
int frontDeque(Deque* deque) {return deque->front->val;
}// 获取双端队列队尾元素
int rearDeque(Deque* deque) {return deque->rear->val;
}// 在双端队列前端插入元素
void addFrontDeque(Deque* deque, int val) {DequeNode* new_node = (DequeNode*)malloc(sizeof(DequeNode));new_node->val = val;new_node->next = deque->front;new_node->prev = NULL;if (deque->front != NULL) {deque->front->prev = new_node;}deque->front = new_node;if (deque->rear == NULL) {deque->rear = new_node;}deque->size++;
}// 在双端队列后端插入元素
void addRearDeque(Deque* deque, int val) {DequeNode* new_node = (DequeNode*)malloc(sizeof(DequeNode));new_node->val = val;new_node->next = NULL;new_node->prev = deque->rear;if (deque->rear != NULL) {deque->rear->next = new_node;}deque->rear = new_node;if (deque->front == NULL) {deque->front = new_node;}deque->size++;
}// 在双端队列前端删除元素
void removeFrontDeque(Deque* deque) {if (deque->front == NULL) {return;}DequeNode* temp = deque->front;deque->front = deque->front->next;if (deque->front != NULL) {deque->front->prev = NULL;} else {deque->rear = NULL;}free(temp);deque->size--;
}// 在双端队列后端删除元素
void removeRearDeque(Deque* deque) {if (deque->rear == NULL) {return;}DequeNode* temp = deque->rear;deque->rear = deque->rear->prev;if (deque->rear != NULL) {deque->rear->next = NULL;} else {deque->front = NULL;}free(temp);deque->size--;
}// 测试
int main() {Deque deque;initDeque(&deque);addFrontDeque(&deque, 1);addRearDeque(&deque, 2);addFrontDeque(&deque, 3);addRearDeque(&deque, 4);while (!isEmptyDeque(&deque)) {printf("%d ", frontDeque(&deque));removeFrontDeque(&deque);}printf("\n");return 0;
}

6.循环队列

        循环队列是一种环形数据结构,它允许在一端添加数据元素,同时在另一端删除数据元素。与线性队列不同的是,在循环队列中,队头和队尾是可以相互穿越的。这意味着队列的末尾可以连接到队列的开始,形成一个环。这样,可以使用有限的空间,存储无限数量的数据元素。

        循环队列通常使用数组来实现。它有一个前后指针,称为队头和队尾。入队操作时,将新元素加入队尾,并将队尾指针向后移动。出队操作时,将队头元素删除,并将队头指针向后移动。当队列满时,新元素无法插入,即使队列前面有空位置。当队列为空时,无法删除元素。

        循环队列的主要优点是可以避免队列的前面空出大量空间,同时保证队列的顺序性和完整性。缺点是在实现时需要注意控制队列满和空的情况,以及指针的计算。

        循环队列是一种特殊的队列,其队尾指针指向数组的末尾后会回到数组的开头,实现队列的循环利用。下面是C语言实现循环队列的示例代码:

#include <stdio.h>
#include <stdlib.h>#define QUEUE_MAX_SIZE 5  // 队列的最大容量typedef struct {int* data;  // 队列数据存储的位置int front;  // 队首指针int rear;   // 队尾指针
} Queue;// 初始化队列
void InitQueue(Queue* q) {q->data = (int*)malloc(QUEUE_MAX_SIZE * sizeof(int));  // 分配队列空间q->front = q->rear = 0;  // 初始化队首和队尾指针
}// 判断队列是否为空
int IsEmpty(Queue* q) {return q->front == q->rear;
}// 判断队列是否已满
int IsFull(Queue* q) {return (q->rear + 1) % QUEUE_MAX_SIZE == q->front;
}// 入队操作
int EnQueue(Queue* q, int value) {if (IsFull(q)) {return 0;  // 队列已满,无法入队}q->data[q->rear] = value;  // 将数据存入队列q->rear = (q->rear + 1) % QUEUE_MAX_SIZE;  // 队尾指针后移return 1;  // 入队成功
}// 出队操作
int DeQueue(Queue* q, int* value) {if (IsEmpty(q)) {return 0;  // 队列为空,无法出队}*value = q->data[q->front];  // 取出队首数据q->front = (q->front + 1) % QUEUE_MAX_SIZE;  // 队首指针后移return 1;  // 出队成功
}// 获取队首元素
int GetFront(Queue* q, int* value) {if (IsEmpty(q)) {return 0;  // 队列为空,无法获取队首元素}*value = q->data[q->front];  // 获取队首元素return 1;  // 获取成功
}// 获取队列长度
int GetLength(Queue* q) {return (q->rear - q->front + QUEUE_MAX_SIZE) % QUEUE_MAX_SIZE;
}// 输出队列中的所有元素
void PrintQueue(Queue* q) {int i, len = GetLength(q);for (i = 0; i < len; i++) {int value;DeQueue(q, &value);printf("%d ", value);EnQueue(q, value);}printf("\n");
}// 测试代码
int main() {Queue q;InitQueue(&q);EnQueue(&q, 1);EnQueue(&q, 2);EnQueue(&q, 3);EnQueue(&q, 4);EnQueue(&q, 5);printf("Queue length: %d\n", GetLength(&q));  // 5printf("Queue content: ");PrintQueue(&q);  // 1 2 3 4 5int value;DeQueue(&q, &value);printf("DeQueue value: %d\n", value);  // 1printf("Queue content: ");PrintQueue(&q);  // 2 3 4 5EnQueue(&q 

        在上面的代码中,我们实现了循环队列的初始化、判断是否为空或已满、入队、出队、获取队首元素、获取队列长度和输出队列中的所有元素等操作。我们可以通过这些操作对循环队列进行基本的操作。 

 🤞❤️🤞❤️🤞❤️队列的知识点总结就到这里啦,如果对博文还满意的话,劳烦各位看官动动“发财的小手”留下您对博文的赞和对博主的关注吧🤞❤️🤞❤️🤞❤️

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Springboot项目升级2.2.x升至2.7.x

依赖管理 spring-boot-starter-parent 升级为2.7.1 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId> <!-- 升级为2.7.x的版本--><version>2.7.1</version>…

计算机竞赛 深度学习 opencv python 公式识别(图像识别 机器视觉)

文章目录 0 前言1 课题说明2 效果展示3 具体实现4 关键代码实现5 算法综合效果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的数学公式识别算法实现 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学…

c++ reference_wrapper源码注释

并给出图片&#xff0c;这样就不用下载了 谢谢

Vue基础之模板语法介绍

前言 上篇我分享了关于Vue的入门&#xff0c;简单的入了个门。本篇文章将要分享的内容为Vue的模板语法。 一、插值 1.1、文本 1.2、html 1.3、属性 1.4、class、style绑定 1.5、表达式 在Vue的模板语法中&#xff0c;插值是一种常用的方式来动态地将数据渲染到视图中。Vue使用双…

Excel打开后关闭就马上跳出 Visual c++ Runtime Error R6025

环境&#xff1a; Win10 专业版 Excel 2016 绿盾加密环境 问题描述&#xff1a; Excel打开后关闭就马上跳出 visual c runtime error R6025 runtime error! program:c:\program files\microsoft office\office14\excle.exe r6025 -pure virtual function call 解决方案…

Spring Boot + Vue3前后端分离实战wiki知识库系统十三--单点登录开发二

接着https://www.cnblogs.com/webor2006/p/17608839.html继续往下。 登录功能开发&#xff1a; 接下来则来开发用户的登录功能&#xff0c;先准备后端的接口。 后端增加登录接口&#xff1a; 1、UserLoginReq&#xff1a; 先来准备用户登录的请求实体&#xff1a; package com…

大模型微调方法

下面是一些参数高效的微调大模型方法&#xff1a; Adapter 模型总览 Adapter作为一个插件加入到大模型内&#xff0c;微调下游任务时&#xff0c;固定大模型参数&#xff0c;只训练Adapter参数。 LoRA LoRA名为大语言模型的低阶适应&#xff0c;最初设计用于微调LLM&#xf…

【面试经典150 | 数组】轮转数组

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;使用额外的数组方法二&#xff1a;翻转数组 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附…

全国职业技能大赛云计算--高职组赛题卷④(容器云)

全国职业技能大赛云计算--高职组赛题卷④&#xff08;容器云&#xff09; 第二场次题目&#xff1a;容器云平台部署与运维任务1 Docker CE及私有仓库安装任务&#xff08;5分&#xff09;任务2 基于容器的web应用系统部署任务&#xff08;15分&#xff09;任务3 基于容器的持续…

RocketMQ 发送顺序消息

文章目录 顺序消息应用场景消息组&#xff08;MessageGroup&#xff09;顺序性生产的顺序性MQ 存储的顺序性消费的顺序性 rocketmq-client-java 示例&#xff08;gRPC 协议&#xff09;1. 创建 FIFO 主题生产者代码消费者代码解决办法解决后执行结果 rocketmq-client 示例&…

CSS动效合集之实现气泡发散动画

前言 &#x1f44f;CSS动效合集之实现气泡发散动画&#xff0c;速速来Get吧~ &#x1f947;文末分享源代码。记得点赞关注收藏&#xff01; 1.实现效果 2.实现步骤 定义一个数组bubbles&#xff0c;用来存储气泡列表的基本新&#xff0c;w表示宽高&#xff0c;x表示绝对定位…

3D医学影像PACS系统源代码

一、系统概述 3D医学影像PACS系统&#xff0c;它集影像存储服务器、影像诊断工作站及RIS报告系统于一身,主要有图像处理模块、影像数据管理模块、RIS报告模块、光盘存档模块、DICOM通讯模块、胶片打印输出等模块组成&#xff0c; 具有完善的影像数据库管理功能&#xff0c;强大…