队列文档之链队

2024-03-23 11:50
文章标签 文档 队列 链队

本文主要是介绍队列文档之链队,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

链队

定义

概念

采用链式存储的队列称为链队。链队是一个同时带有队头指针和队尾指针的单链表。其中队头指针始终指向队头结点,队尾指针始终指向队尾结点(即单链表的最后一个结点)。

注:链式队列和顺序队列的队尾指针指向不同,在顺序队列中队尾指针指向队尾元素的下一个位置,在链式队列中队尾指针指向队尾结点。

在这里插入图片描述

结构体

链队中元素结点结构体定义:

/*** 链队列中的结点结构体定义*/
typedef struct QNode {/*** 结点数据域,存储链队列中结点的数据*/int data;/*** 结点指针域,存储当前结点的后继结点的地址*/struct QNode *next;
} QNode;

链队结构体定义:


/*** 链队列结构体定义*/
typedef struct {/*** 存储链队列的队头结点的地址,即指向队头结点*/QNode *front;/*** 存储链队列的队尾结点的地址,即指向队尾结点*/QNode *rear;
} LinkedQueue;

特点

  • queue->rear==NULL 或者 queue->front==NULL 时队空。
  • 不存在队满的情况,假设内存无限大的情况下。
  • 队头指针 front 始终指向队头结点;队尾指针 rear 始终指向队尾结点。
  • 入队操作:创建新结点,将新结点插入到链表的尾部,并让队尾指针 rear 指向这个新结点。如果原队列为空,那么让队头指针 front 也指向该结点。
  • 出队操作:首先判断队列是否为空,若不为空,则取出队头指针 front 所指向的结点元素,将其从链表中摘除,并让队头指针 front 指向其后继结点。如果该结点是最后一个结点,则将队头指针 front 和队尾指针 rear 都指向 NULL
  • 不带头结点的链式队列在操作上比较麻烦,因此通常将链式队列设计成一个带头结点的单链表,这样插入和删除操作就统一了。
  • 用单链表表示的链式队列特别适合数据元素变动比较大的情况,并且不存在队列满而产生的溢出问题。

基本操作

注,完整代码请参考:

  • LinkedQueue.c
  • LinkedQueue.java
  • LinkedQueueTest.java

概述

链队的常见操作如下:

  • void init(LinkedQueue **queue):初始化链队。其中 queue 表示链队。
  • int isEmpty(LinkedQueue *queue):判断链队是否为空。其中 queue 表示链队。如果链队为空则返回 1,否则返回 0 表示非空。
  • int enQueue(LinkedQueue **queue, int ele):将元素进队。其中 queue 表示链队;ele 表示待插入的新元素值。如果链队为满则不能入队,则返回 0;如果入队成功则返回 1 表示成功。
  • int deQueue(LinkedQueue **queue, int *ele):将元素出队。其中 queue 表示链队。ele 用来存放出队的元素。如果链队为空则不能出队,则返回 0;如果出队成功则返回 1 表示成功。
  • int size(LinkedQueue *queue):获取链队的长度。其中 queue 表示链队。返回链队中元素个数。
  • int getFront(LinkedQueue *queue, int *ele):获取链队队头元素。其中 queue 表示链队;ele 用来存放队头元素。如果链队为空则无法获取队头元素则返回 0,否则返回 1。
  • int getRear(LinkedQueue *queue, int *ele):获取链队队尾元素。其中 queue 表示链队;ele 用来存放队尾元素。如果链队为空则无法获取队尾元素则返回 0,否则返回 1。
  • void print(LinkedQueue *queue):打印链队中所有元素。其中 queue 表示链队。
  • void clear(LinkedQueue **queue):清空链队所有元素。其中 queue 表示链队。
  • void destroy(LinkedQueue **queue):销毁链队。其中 queue 表示链队。

init

初始化链队。

在这里插入图片描述

实现步骤:

  • 创建链队头结点,将头结点的 front 指针和 rear 指针都指向 NULL,表示是空队列。

实现代码如下:

/*** 初始化链队列* @param queue 未初始化的链队列*/
void init(LinkedQueue **queue) {// 其实 queue 就相当于链队列的头结点,不过它有两个指针,分别存储队头结点和队尾结点的地址// 为链队列头结点分配存储空间*queue = (LinkedQueue *) malloc(sizeof(LinkedQueue));// 将队头指针和队尾指针都指向 NULL,表示空队列(*queue)->front = NULL;(*queue)->rear = NULL;
}

isEmpty

判断链队是否为空,如果为空则返回 1,否则返回 0 表示非空。

在这里插入图片描述

实现步骤:

  • 判断链队的队头指针 front 或者队尾指针 rear 是否指向 NULL,如果是则表示空队列则返回 1,否则如果不是空队列则返回 0。

实现代码如下:

/*** 判断链队列是否为空* @param queue 链队列* @return 如果链队列为空则返回 1,否则返回 0 表示非空*/
int isEmpty(LinkedQueue *queue) {// 只要链队列的队头指针或者队尾指针指向 NULL 则表示是空队if (queue->front == NULL || queue->rear == NULL) {return 1;} else {return 0;}
}

enQueue

将元素入队。

在这里插入图片描述

在这里插入图片描述

实现步骤:

  • 创建新结点,为新结点分配空间,指定数据域为 ele,指定指针域初始指向 null,表示这是一个新结点。
  • 判断队列是否为空。如果队列为空,则新结点入队,既是队头结点也是队尾结点。即将队头指针 front 和队尾指针 rear 都指向新结点。
  • 如果队列非空,则将新结点插入到队尾结点的后面,然后将队尾指针 rear 指向新结点。

实现代码如下:

/*** 将元素入队* @param queue 链队列* @param ele 待入队的元素*/
void enQueue(LinkedQueue **queue, int ele) {// 0.因为是链表来表示队列,理论上不存在队满的情况,所以不需要校验队满// 1.创建新结点// 1.1 为新结点分配空间QNode *newNode = (QNode *) malloc(sizeof(QNode));// 1.2 为新结点指定数据域newNode->data = ele;// 1.3 为新结点指定数据域,初始指向 NULLnewNode->next = NULL;// 2.将新结点入队// 2.1 若队列为空,则新结点是队头结点,也是队尾结点if ((*queue)->rear == NULL) {// 因为链队列只有一个结点,所以将队头指针和队尾指针都指向新结点(*queue)->front = newNode;(*queue)->rear = newNode;}// 2.2 如果队列非空,则将新结点插入到队尾结点的后面,并将队尾指针指向新结点else {// 局部变量,记录队尾结点QNode *tailNode = (*queue)->rear;// 2.2.1 将新结点插入到队尾结点的后面tailNode->next = newNode;// 2.2.2 将队尾指针指向新结点(*queue)->rear = newNode;}
}

deQueue

将元素出队,即从链队的头部出队。如果不是空队列才能出队,用 ele 保存出队元素的值,然后返回 1 表示出队成功;如果是空队列,则返回 0 表示出队失败。

在这里插入图片描述
在这里插入图片描述

实现步骤:

  • 参数校验,如果队空则不能出队。返回 0 表示出队失败。
  • 用 ele 保存队头结点的元素值。
  • 判断如果队列中只有一个元素(当队头指针和队尾指针指向同一个结点时就表示队列中只有一个元素),那么将队头指针 front 和队尾指针 rear 都指向 NULL。因为只有一个元素出队后,队列就会变成空队列。
  • 如果队列中不止一个元素,那么将队头指针 front 指向下一个结点。
  • 然后释放原队头结点的空间。
  • 返回 1 表示出队成功。

实现代码如下:

/*** 将元素出队* @param queue 链队列* @param ele 用来保存出队元素* @return 如果链队列为空则不能出队则返回 0 表示出队失败;否则返回 1 表示出队成功*/
int deQueue(LinkedQueue **queue, int *ele) {// 0.参数校验,如果队空则不能出队if ((*queue)->front == NULL || (*queue)->rear == NULL) {return 0;}// 1.将队头结点出队// 1.1 变量,记录链队列的队头结点QNode *frontNode = (*queue)->front;// 1.2 用 ele 保存队头结点的数据域,即要出队的结点值*ele = frontNode->data;// 1.3 删除队头结点并修改队头指针// 1.3.1 如果队列中只有一个结点时的出队操作需要特殊处理,因为需要将队头指针和队尾指针都指向 NULLif ((*queue)->front == (*queue)->rear) {(*queue)->front = NULL;(*queue)->rear = NULL;}// 1.3.2 当队列不止一个结点时,将队头指针指向原队头结点的后继结点else {(*queue)->front = frontNode->next;}// 1.4 释放原队头结点free(frontNode);// 1.5 返回 1 表示出队成功return 1;
}

size

统计链队中的结点个数。

在这里插入图片描述

实现步骤:

  • 声明局部变量 len,用于记录链队的结点个数。

  • 从队头结点(即队头指针所指向的结点)开始扫描整个单链表,每个结点出现一次那么变量 len 便加一。

  • 最后返回统计结果。

实现代码如下:

/*** 获取链队列中的结点个数* @param queue 链队列* @return 结点个数*/
int size(LinkedQueue *queue) {// 变量,记录链队列结点个数int len = 0;// 变量,结点链队列的队头结点,相当于单链表的开始结点QNode *node = queue->front;// 扫描链队列,即遍历单链表,统计结点个数while (node != NULL) {len++;node = node->next;}return len;
}

getFront

读取队头元素。如果队列非空,则获取队头结点的元素值,用 ele 保存,然后返回 1 表示获取成功。如果队列为空则返回 0 表示获取失败。

在这里插入图片描述

实现步骤:

  • 参数校验,如果队列为空则返回 0。
  • 用 ele 保存队头指针所指向的结点的值。因为链队中队头指针始终指向队头结点。
  • 返回 1 表示获取成功。

实现代码如下:

/*** 获取链队列的队头结点数据值* @param queue 链队列* @param ele 用来保存队头结点数据值* @return 如果链队列为空则返回 0 表示获取失败,否则返回 1 表示获取成功*/
int getFront(LinkedQueue *queue, int *ele) {// 0.参数校验,如果链队列为空,则表示不能获取队头元素if (queue->front == NULL || queue->rear == NULL) {return 0;}// 1.用 ele 保存队头结点的数据值,即队头指针所指向的结点*ele = queue->front->data;return 1;
}

getRear

读取队尾元素。如果队列非空,则获取队尾结点的元素值,用 ele 保存,然后返回 1 表示获取成功。如果队列为空则返回 0 表示获取失败。

在这里插入图片描述

实现步骤:

  • 参数校验,如果队列为空则返回 0。
  • 用 ele 保存队尾指针所指向的结点的值。因为链队中队尾指针始终指向队尾结点。
  • 返回 1 表示获取成功。

实现代码如下:

/*** 获取链队列的队尾结点数据值* @param queue 链队列* @param ele 用来保存队尾结点数据值* @return 如果链队列为空则返回 0 表示获取失败,否则返回 1 表示获取成功*/
int getRear(LinkedQueue *queue, int *ele) {// 0.参数校验,如果链队列为空,则表示不能获取队尾元素if (queue->front == NULL || queue->rear == NULL) {return 0;}// 1.用 ele 保存队尾结点的数据值,即队尾指针所指向的结点*ele = queue->rear->data;return 1;
}

print

打印链队中所有元素。

在这里插入图片描述

实现步骤:

  • 从队头结点开始,扫描整个队列(即单链表),打印每个结点的数据值。

实现代码如下:

/*** 打印链队列的所有结点值* @param queue 链队列*/
void print(LinkedQueue *queue) {printf("[");QNode *frontNode = queue->front;while (frontNode != NULL) {printf("%d", frontNode->data);if (frontNode->next != NULL) {printf(", ");}frontNode = frontNode->next;}printf("]\n");
}

clear

清空链队。

在这里插入图片描述

实现步骤:

  • 从队头结点开始,扫描链队中的所有结点,释放每一个结点的存储空间。
  • 最后将链队头结点的队头指针 front 和队尾指针 rear 指向 NULL,表示是空队。

实现代码如下:

/*** 清空链队列* @param queue 链队列*/
void clear(LinkedQueue **queue) {// 变量,记录链队列中的节点,初始为链队列的队头结点QNode *frontNode = (*queue)->front;// 扫描链队列所有结点,释放每个结点的空间while (frontNode != (*queue)->rear) {// 保存当前节点的后继结点,因为要释放结点,所以需要提前保存QNode *temp = frontNode->next;// 释放当前节点free(frontNode);// 继续链队列的下一个结点frontNode = temp;}// 最后链队列头结点的队头指针和队尾指针都指向 NULL 表示空队列(*queue)->front = NULL;(*queue)->rear = NULL;
}

destroy

销毁链队。

实现步骤:

  • 释放链队头结点的存储空间。

实现代码如下:

/*** 销毁链队列* @param queue 链队列*/
void destroy(LinkedQueue **queue) {// 即释放链队列头结点的空间free(*queue);
}

注意事项

无。

练习题

  • Example002-用带头结点的循环链表表示队列,并且只设一个指针指向队尾结点,实现对应的入队列和出队列的算法
  • Example006-设计队列要求入队时增加队列空间,出队后出队元素所占用空间可重复使用,以保持队列空间只增不减,并且要求入队操作和出队操作的时间复杂度都为O(1)

这篇关于队列文档之链队的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/838232

相关文章

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 2431 poj 3253 优先队列的运用

poj 2431: 题意: 一条路起点为0, 终点为l。 卡车初始时在0点,并且有p升油,假设油箱无限大。 给n个加油站,每个加油站距离终点 l 距离为 x[i],可以加的油量为fuel[i]。 问最少加几次油可以到达终点,若不能到达,输出-1。 解析: 《挑战程序设计竞赛》: “在卡车开往终点的途中,只有在加油站才可以加油。但是,如果认为“在到达加油站i时,就获得了一

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

poj3750约瑟夫环,循环队列

Description 有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。 Input 第一行输入小孩的人数N(N<=64) 接下来每行输入一个小孩的名字(人名不超过15个字符) 最后一行输入W,S (W < N),用

POJ2010 贪心优先队列

c头牛,需要选n头(奇数);学校总共有f的资金, 每头牛分数score和学费cost,问合法招生方案中,中间分数(即排名第(n+1)/2)最高的是多少。 n头牛按照先score后cost从小到大排序; 枚举中间score的牛,  预处理左边与右边的最小花费和。 预处理直接优先队列贪心 public class Main {public static voi

Java并发编程之——BlockingQueue(队列)

一、什么是BlockingQueue BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种: 1. 当队列满了的时候进行入队列操作2. 当队列空了的时候进行出队列操作123 因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空

FreeRTOS学习笔记(六)队列

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、队列的基本内容1.1 队列的引入1.2 FreeRTOS 队列的功能与作用1.3 队列的结构体1.4 队列的使用流程 二、相关API详解2.1 xQueueCreate2.2 xQueueSend2.3 xQueueReceive2.4 xQueueSendFromISR2.5 xQueueRecei

Python脚本:TXT文档行数统计

count = 0 #计数变量file_dirs = input('请输入您要统计的文件根路径:')filename = open(file_dirs,'r') #以只读方式打开文件file_contents = filename.read() #读取文档内容到file_contentsfor file_content in file_contents: