当前位置: 首页 > news >正文

数据结构 --- 队列

队列 --- Queue

  • 前言
  • 一、整体结构
  • 二、相关方法
    • 1.初始化
    • 2.销毁
    • 3.入队 - - - 队尾插插入数据
    • 4.出队 - - - 队头删除数据
    • 5.获取队头 / 队尾元素
    • 6.判空
    • 7.获取队列有效元素个数

前言

队列是一种特殊的线性表,其特性是先进先出,只能在队尾入数据,在队头出数据,本次实现使用链表结构实现队列,对比数组实现有下列优点:
在这里插入图片描述

尽管现在来看两者的时间复杂度是差不多的,但是对于链表来说,我们只需要再定义一个尾节点来表示队尾即可将入队操作的时间复杂度优化为O(1),而数组的出队操作是无法优化时间复杂度的,所以综上所述本次实现选择链表结构实现队列。故而逻辑结构上是线性的,物理结构上不一定是线性的
本次实现使用C语言实现

一、整体结构

本次实现队列底层结构是链表,所以说有一个节点结构类型,并且队列操作数据只有队头和队尾位置可以操作,所以将其抽离出来,这就是队列的结构。

节点的结构:

typedef int QDataType;
// 队列的节点结构
typedef struct QueueNode
{QDataType data;          // 数据域struct QueueNode* next;  // 指针域
}QueueNode;

队列的结构:

// 队列的结构
typedef struct Queue
{QueueNode* phead;     // 队头QueueNode* ptail;     // 队尾// int size;          // 有效数据个数
}Queue;

二、相关方法

1.初始化

初始化即将队列phead和ptail置为空即可。

// 初始化
void QueueInit(Queue* pq)
{// pq不能为空assert(pq);// 初始化成空pq->phead = pq->ptail = NULL;// pq->size = 0;
}

创建一个空队列q1并初始化它,
监视窗口演示:
在这里插入图片描述

2.销毁

常见的标记销毁位置起始的节点,并记录此位置的下一个节点,之后循环销毁节点,完成后将phead和ptail置为NULL。

// 销毁
void QueueDestroy(Queue* pq)
{assert(pq);// 标记队头QueueNode* pcur = pq->phead;// 销毁节点while (pcur){// 记录pcur的下一个节点QueueNode* pnext = pcur->next;free(pcur);pcur = pnext;}// 销毁完成后phead和ptail置为NULLpq->phead = pq->ptail = NULL;// pq->size =0;
}

3.入队 - - - 队尾插插入数据

入队两步骤:
1)申请新节点,动态开辟(malloc)一个节点大小的内存空间,更新数据域为入队元素x,再将指针域置为NULL。
2)判断队列是否有元素,若有元素则直接在队尾ptail后面插入数据,并更新队尾指针指向;若没有元素,则新插入的节点newnode既是队头phead也是队尾ptail。

// 入队 --- 队尾入
void QueuePush(Queue* pq, QDataType x)
{assert(pq);// 申请新节点QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("malloc");exit(1);}newnode->data = x;newnode->next = NULL;// 当队列为空时if (pq->phead == NULL){// 新节点就是队头和队尾pq->phead = pq->ptail = newnode;}// 当队列不为空时else{// 队尾入队列pq->ptail->next = newnode;// 移动队尾指针pq->ptail = pq->ptail->next;}// pq->size++;
}

向初始化完成后的队列q1入队三个数据:10,20,30
监视窗口演示:
在这里插入图片描述

4.出队 - - - 队头删除数据

出队两步骤:
1)判断队列是否是非空状态,只有有元素才可以出队。
2)判断队列的节点个数,当只有一个节点时,销毁此节点并将phead和ptail置为NULL;当有多个节点时,也是销毁此节点,并更新队头指针。

// 出队 --- 队头出
void QueuePop(Queue* pq)
{// 队列非空才可以出队assert(!QueueEmpty(pq));// 当队列只有一个节点if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;}// 当队列有多个节点时else{// 标记队头的下一个节点QueueNode* pnext = pq->phead->next;free(pq->phead);// 移动队头至下一个节点pq->phead = pnext;}//pq->size--;
}

向入队完成后的队列q1出队前两个数据:10,20
监视窗口演示:
在这里插入图片描述

5.获取队头 / 队尾元素

获取两者的元素各自访问队头队尾指针的数据域即可,前提是队列非空。

获取队头元素:

// 获取队头元素
QDataType QueueFront(Queue* pq)
{// 队列非空才可以获取assert(!QueueEmpty(pq));return pq->phead->data;
}

获取队尾元素:

// 获取队尾元素
QDataType QueueBack(Queue* pq)
{// 队列非空才可以获取assert(!QueueEmpty(pq));return pq->ptail->data;
}

6.判空

队列为空的条件是队头指针或者队尾指针等于NULL。

// 判空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}

7.获取队列有效元素个数

有两种方法:
1)遍历队列,定义一个计数器size,每访问一个节点计数器加一。
2)在队列属性里多增加一个size属性,直接返回size即可,增加这一个属性之后,初始化,入队,出队,销毁这种需要改变size大小的方法也需要对size进行操作。

// 获取队列有效元素个数
int Queuesize(Queue* pq)
{// 方法一:遍历,统计// 适用于非频繁访问有效数据个数的场景 : O(N)// 标记队头QueueNode* pcur = pq->phead;int size = 0;while (pcur){size++;pcur = pcur->next;}return size;// 方法二:给队列增加一个size属性// 适用于频繁访问有效数据个数的场景 :O(1)//return pq->size;
}
http://www.lryc.cn/news/584729.html

相关文章:

  • XCZU47DR-2FFVG1517I Xilinx FPGA AMD ZynqUltraScale+ RFSoC
  • 超声波刻刀适用于一些对切割精度要求高、材料厚度较薄或质地较软的场景,典型应用场景如下:
  • 测试开发和后端开发到底怎么选?
  • UGF开发记录_3_使用Python一键转换Excle表格为Txt文本
  • 穿梭时空的智慧向导:Deepoc具身智能如何赋予导览机器人“人情味”
  • Qt中处理多个同类型对象共享槽函数应用
  • 广州华锐互动在各领域打造的 VR 成功案例展示​
  • pycharm无法识别pip安装的包
  • 【佳易王中药材划价软件】:让中药在线管理高效化、复制文本即可识别金额自动计算#中药房管理工具#快速划价系统#库存与账单一体化解决方案,软件程序操作教程详解
  • 多线程 JAVA
  • MySQL索引操作全指南:创建、查看、优化
  • H5微应用四端调试工具—网页版:深入解析与使用指南
  • 7月10号总结 (1)
  • C++ Lambda 表达式详解
  • 数据结构 顺序表(1)
  • linux-MySQL的安装
  • [数据结构与算法] 优先队列 | 最小堆 C++
  • 7-语言模型
  • 数据仓库:企业数据管理的核心枢纽
  • 基于模糊控制及BP神经网络开关磁阻电机的matlab仿真
  • 量子计算系统软件:让“脆弱”的量子计算机真正可用
  • 《Effective Python》第十三章 测试与调试——使用 Mock 测试具有复杂依赖的代码
  • Three.js+Shader实现三维波动粒子幕特效
  • 1.1.1数据类型与变量——AI教你学Django
  • SQLite3 中列(变量)的特殊属性
  • 【c++八股文】Day6:using和typedef
  • MiniGPT4源码拆解——models
  • vscode和插件用法
  • imx6ull-裸机学习实验17——SPI 实验
  • 【会员专享数据】2013-2024年我国省市县三级逐年SO₂数值数据(Shp/Excel格式)