数据结构-队列

数据结构之队列

    • 队列的概念
      • 顺序队列
      • 循环队列
    • 顺序循环队列的ADT定义
      • 1、简单结构体定义
      • 2、初始化
      • 3、队列的清空
      • 4、计算队列的长度
      • 5、判断队列是否为空
      • 6、插入新的元素
      • 7、元素的删除
      • 8、遍历输出队列内的所有元素
    • 链队列的ADT定义
      • 1、链队列简单结构体定义
      • 2、初始化链队列
      • 3、判断链队列是否为空
      • 4、清空链队列
      • 5、销毁链队列
      • 6、获取链队列的长度
      • 7、获取链队列的头元素
      • 8、在链队列尾插入新元素
      • 9、删除链队列的头元素
      • 10、遍历链队列中的元素
    • 顺序队列和链式队列的比较

队列的概念

队列(queue)和栈类似,队列中的数据也呈线性排列,但是队列中添加和删除数据的操作分别是在两端进行。就和“ 队列” 这个名字一样,把它想象成排成一队的人更容易理解。在队列中,处理总是从第一个位置开始往后进行,而新来的人只能排在最后的位置。
队列是只允许在一端进行插入操作,在另一端进行删除操作,是一种先进先出的线性表, First In First Out,简称FIFO。允许插入的一 端称为队尾,允许删除的一端称为队头。
在这里插入图片描述
线性表有顺序存储和链式存储两种形式,队列作为一种特殊的线性表,也存在着这两种存储方式。

顺序队列

顺序存储形式的队列,是利用一组地址连续的存储单元,每个存储单元依次存放队列中的元素。为了避免当只有一个元素时,队头和队尾重合使得处理变得麻烦,所以引入两个指针(头指针和尾指针):头指针front指针指向队头元素,尾指针rear指针指向队尾元素的下一个位置。初始化时的头尾指针,初始值均为0。
入队时尾指针rear加1,出队时头指针front加1,头尾指针相等时队列即为空。

当尾指针已经指向了队列的最后一个位置的下一位置时,若再有元素入队,就会发生“溢出”。
为了解决溢出问题,可以采用循环队列。

循环队列

使用循坏队列,将新元素再插入到第一个位置上,入队和出队仍按先进先出的原则进行,操作效率高,空间利用率高,同时解决了顺序队列的假溢出问题。
在这里插入图片描述
但是,同时仅凭 front = rear 不能判定循环队列是空还是满
判断队空或者队满,有三种方式:

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

顺序循环队列的ADT定义

1、简单结构体定义

typedef int Status;
typedef int QElemType; // QElemType类型根据实际情况而定,这里假设为int 

// 循环队列的顺序存储结构
typedef struct
{
    QElemType data[MAXSIZE];
    int front;      // 头指针
    int rear;       // 尾指针,若队列不空,指向队列尾元素的下一个位置 
}SqQueue;

2、初始化

Status InitQueue(SqQueue *Q)
{
    Q->front = 0;
    Q->rear = 0;
    return  TRUE;
}

3、队列的清空

Status ClearQueue(SqQueue *Q)
{
    Q->front = Q->rear = 0;
    return TRUE;
}

4、计算队列的长度

int QueueLength(SqQueue Q)
{
    return  (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

5、判断队列是否为空

若队列不空,则用e返回Q的队头元素,并返回TRUE,否则返回FALSE

Status GetHead(SqQueue Q, QElemType *e)
{
    if (Q.front == Q.rear) /* 队列空 */
        return FALSE;
    *e = Q.data[Q.front];
    return TRUE;
}

6、插入新的元素

若队列未满,则插入元素e为Q新的队尾元素

Status EnQueue(SqQueue *Q, QElemType e)
{
    if ((Q->rear + 1) % MAXSIZE == Q->front)    // 队列满的判断 
        return FALSE;
    Q->data[Q->rear] = e;           // 将元素e赋值给队尾
    Q->rear = (Q->rear + 1) % MAXSIZE;// rear指针向后移一位置,若到最后则转到数组头部 
    return  TRUE;
}

7、元素的删除

若队列不空,则删除Q中队头元素,用e返回其值

Status DeQueue(SqQueue *Q, QElemType *e)
{
    if (Q->front == Q->rear)  //*队列空的判断
        return FALSE;
    *e = Q->data[Q->front];  // 将队头元素赋值给e
    Q->front = (Q->front + 1) % MAXSIZE; //front指针向后移一位置,到了最后则转到数组头部
    return  TRUE;
}

8、遍历输出队列内的所有元素

队头到队尾依次对队列Q中每个元素输出

Status QueueTraverse(SqQueue Q)
{
    int i;
    i = Q.front;
    while ((i + Q.front) != Q.rear)
    {
        visit(Q.data[i]);
        i = (i + 1) % MAXSIZE;
    }
    printf("\n");
    return TRUE;
}

链队列的ADT定义

队列的链式存储结构,就是一个单向链表。链式队列和单向链表比就多了两个指针,头指针和尾指针。

优点:
相比普通的队列,元素出队时无需移动大量元素,只需移动头指针。
可动态分配空间,不需要预先分配大量存储空间。
适合处理用户排队等待的情况。
缺点:
需要为表中的逻辑关系增加额外的存储空间。

读取时的时间复杂度为O(1)。
插入、删除时的时间复杂度为O(1)。

1、链队列简单结构体定义

typedef int Status; // 函数返回结果类型
typedef int ElemType; // 元素类型

// 队列节点
typedef struct QNode {
    ElemType data; // 元素值
    struct QNode *next; // 指向下一个节点的指针
} QNode, *QueuePtr;

// 链队列结构
typedef struct {
    QueuePtr front, rear; // 队头指针、队尾指针
} LinkQueue;

2、初始化链队列

Status InitQueue(LinkQueue *Q) {
    // 为队头和队尾指针分配内存
    Q->front = Q->rear = (QueuePtr) malloc(sizeof(QNode));

    // 内存分配失败,结束程序
    if (!Q->front || !Q->rear) {
        return FALSE;
    }
    Q->front->next = NULL; // 队头节点指向NULL
    return TRUE;
}

3、判断链队列是否为空

Status QueueEmpty(LinkQueue Q) {
    // 头指针和尾指针位置相等,队列为空
    if (Q.front == Q.rear) {
        return TRUE;
    } else {
        return FALSE;
    }
}

4、清空链队列

Status ClearQueue(LinkQueue *Q) {
    QueuePtr p, q; // p用来遍历队列节点,q用来指向被删除的节点

    Q->rear = Q->front; // 队尾指针指向队头指针
    p = Q->front->next; // p指向队头指针的下一个节点
    Q->front->next = NULL; // 队头指针的下一个节点指向NULL(表示删除之后的所有元素)
    // 当队列中还有元素,释放头节点之后的所有节点
    while (p) {
        q = p; // q节点指向被删除节点
        p = p->next; // p指向队列的下一个节点
        delete q; // 释放q节点
    }
    return TRUE;
}

5、销毁链队列

Status DestroyQueue(LinkQueue *Q) {
    // 当队列中还有元素
    while (Q->front) {
        Q->rear = Q->front->next;// 队尾指针指向队头指针的下一个元素
        delete Q->front; // 释放队头指针所在节点
        Q->front = Q->rear; // 队头指针指向队尾指针(即原来的下一个元素)
    }
    return TRUE;
}

6、获取链队列的长度

int QueueLength(LinkQueue Q) {
    int i = 0; // 用于统计队列长度的计数器
    QueuePtr p; // 用于遍历队列的元素
    p = Q.front; // p指向队头节点

    // 当p没有移动到队尾指针位置
    while (p != Q.rear) {
        i++; // 计数器加1
        p = p->next; // p移动到队列的下一个节点
    }
    return i; // 返回队列长度
}

7、获取链队列的头元素

Status GetHead(LinkQueue Q, ElemType *e) {
    QueuePtr p;

    // 队列为空,获取失败
    if (Q.front == Q.rear) {
        return FALSE;
    }

    p = Q.front->next; // p指向队列的第一个元素
    *e = p->data; // 将队列头元素的值赋值给e元素
    return TRUE;
}

8、在链队列尾插入新元素

Status EnQueue(LinkQueue *Q, ElemType e) {
    // 给新节点分配空间
    QueuePtr s = (QueuePtr) malloc(sizeof(QNode));

    // 分配空间失败,结束程序
    if (!s) {
        return FALSE;
    }

    s->data = e; // 将值赋值给新节点
    s->next = NULL; // 新节点指向NULL
    Q->rear->next = s; // 队尾指针的下一个元素指向新节点
    Q->rear = s; // 队尾指针指向新节点(新节点成为队尾指针的指向的节点)
    return TRUE;
}

9、删除链队列的头元素

Status DeQueue(LinkQueue *Q, ElemType *e) {
    QueuePtr p; // 用于指向被删除节点

    // 队列为空,出队失败
    if (Q->front == Q->rear) {
        return FALSE;
    }

    p = Q->front->next; // p指向队列的第一个元素
    *e = p->data; // 将队列头节点的值赋值给元素e
    Q->front->next = p->next; // 头指针的下一个节点指向下下个节点(跳过头节点)

    // 如果被删除节点是队尾指针指向的节点(删除后队列为空)
    if (Q->rear == p) {
        Q->rear = Q->front; // 队尾指针指向队头指针
    }
    delete p; // 释放队头节点
    return TRUE;
}

10、遍历链队列中的元素

Status QueueTravel(LinkQueue Q) {
    QueuePtr p; // 用于遍历队列中的节点

    p = Q.front->next; // p指向头节点

    printf("[ ");
    // 当队列中还有元素
    while (p) {
        printf("%d ", p->data); // 打印当前节点的值
        p = p->next; // p移动到队列下一个位置
    }
    printf("]\n");
    return TRUE;
}

顺序队列和链式队列的比较

顺序队列是以数组的形式实现的,首指针在出队的时候向后移动,尾指针在入队的时候向后移动,需要考虑队列为空、队列为满的两种情况。

链式队列是以链表的形式实现的,首指针不移动始终指向头节点,尾指针在入队的时候移动指向插入的元素,只考虑队列为空的情况
(只要存储空间够,就能申请内存空间来存放节点,所以不用考虑满,因为链表长度在程序运行过程中可以不断增加)

参考资料:数据结构与算法基础-王卓老师

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

神秘的临时对象

下面的程序输出什么?为什么? 程序意图: 在 Test() 中以 0 作为参数调用 Test(int i) 将成员变量 mi 的初始值设置为 0 运行结果: 成员变量 mi 的值为随机值 构造函数是一个特殊的函数 是否可以直接调用? 是否可以…

LVS+KeepAlived高可用负载均衡集群

LVSKeepAlived高可用负载均衡集群 1. 高可用群集的相关知识1.普通群集2.高可用群集(HA)3.Keepalived及其工作原理4.Keepalived体系主要模块及其作用5.健康检查方式(学名:探针) 二、脑裂的形成和解决1.产生脑裂的常见原因及解决方法2.脑裂预防…

谈找工作线上途径

谈找工作 目录概述需求: 设计思路实现思路分析1.51job2.拉勾网 猎聘网站智联招聘网站后记 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait…

新能源汽车保养vr仿真教学软件为职业培训带来新的思路和方法

电动车电池更换VR虚拟体验是一种利用VR虚拟现实技术实现对电动车电池更换进行模拟仿真演示和实操训练的虚拟仿真实验教学课件,相比传统教学模式,有效提高学生的实践能力和技能水平。 通过VR技术模拟现场,使培训人员可以身临其境滴观摩操作过程…

在 PyTorch 中实现可解释的神经网络模型

动动发财的小手,点个赞吧! 目的 深度学习系统缺乏可解释性对建立人类信任构成了重大挑战。这些模型的复杂性使人类几乎不可能理解其决策背后的根本原因。 ❝ 深度学习系统缺乏可解释性阻碍了人类的信任。 ❞ 为了解决这个问题,研究人员一直在…

c++Qt Creator调用 python 完整版 + 解决bug过程

文章目录 创建项目配置python环境导入Python库其他坑点Python.h 头文件报错ModuleNotFoundError: No module named encodings’ 完美解决找不到python文件 成功! 文章首发于我的个人博客:欢迎大佬们来逛逛 创建项目 选择创建 qmake 项目: …

【C++】vector的模拟实现

目录 1.vector的结构2.构造函数2.1 无参构造2.2 以迭代器区间作为参数的构造函数2.3 构造n个value值 3.拷贝构造3.1 传统写法3.2 现代写法 4.赋值重载5.迭代器失效问题5.1 reserve和resize5.2 insert 5.3 erase4. 整体代码(包含迭代器、析构函数等) 1.ve…

springboot实验室管理系统-计算机毕设 附源码86757

springboot实验室管理系统 摘 要 验室管理系统是将实验室的分析仪器通过计算机网络连起来,采用科学的管理思想和先进的数据库技术,实现以实验室为核心的整体环境的全方位管理。它集用户管理,实验室信息管理,实验室预约管理&#x…

Java设计模式——策略模式

1. 策略模式简介 策略模式: 策略模式是一种行为型模式, 它将对象和行为分开, 将行为定义为一个行为接口和具体行为的实现 策略模式最大的特点是行为的变化, 行为之间可以相互替换 每个if判断都可以理解为一个策略. 本模式是的算法可独立于使用它的用户而变化 2. 模式结构 策略…

Flink 学习七 Flink 状态(flink state)

Flink 学习七 Flink 状态(flink state) 1.状态简介 流式计算逻辑中,比如sum,max; 需要记录和后面计算使用到一些历史的累计数据, 状态就是:用户在程序逻辑中用于记录信息的变量 在Flink 中 ,状态state 不仅仅是要记录状态;在程序运行中如果失败,是需要重新恢复,所以这个状态…

Java实训第七天——2023.6.13

文章目录 一、用Visual Studio Code写一个计算器二、同一个js被多个html引用三、js操作css四、DOM对象属性的操作案例五、js解析json 一、用Visual Studio Code写一个计算器 功能&#xff1a;实现简单的加减乘除 <!DOCTYPE html> <html lang"en"> <…

LeetCode 2481. 分割圆的最少切割次数

【LetMeFly】2481.分割圆的最少切割次数 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-cuts-to-divide-a-circle/ 圆内一个 有效切割 &#xff0c;符合以下二者之一&#xff1a; 该切割是两个端点在圆上的线段&#xff0c;且该线段经过圆心。该切割是一端…

mapbox-gl 点位编辑功能

文章目录 前言方式一&#xff1a;借助 Marker添加自定义icon添加POI图层&#xff0c;绑定对应事件基于Marker交互创建自定义Marker编辑 / 创建POI 方式二&#xff1a;采用 mapbox-gl-draw 插件总结 前言 矢量在线编辑是gis常用的编辑功能&#xff0c;兴趣点&#xff08;POI&am…

kettle开发-Day38-超好用自定义数据处理组件

目录 前言&#xff1a; 一、半斤八两&#xff0c;都不太行 1、表输入&#xff0c;速度快&#xff0c;但不稳妥 2、稳的一批&#xff0c;但是慢的像蜗牛 二、各诉衷肠&#xff0c;合作共赢 1、表输入&#xff0c;高效数据插入 2、插入更新&#xff0c;一个都不能少 三、表输…

express的使用(四) nodejs转发表单到后台

原文链接 搬砖的林小白-express的使用(四) 个人博客地址&#xff0c;求关注&#xff0c;也希望大家在里面批评我的不足之处 看前提示 本篇所讲述的内容是node端转发前端发送过来的表单到第三方中&#xff0c;应用的场景有很多&#xff0c;如我们经常做的将文件存储到七牛云或…

Scala学习笔记

累了&#xff0c;基础配置不想写了&#xff0c;直接抄了→Scala的环境搭建 这里需要注意的是&#xff0c;创建新项目时&#xff0c;不要用默认的Class类&#xff0c;用Object&#xff0c;原因看→scala中的object为什么可以直接运行 一、Scala简介 1.1 图解Scala和Java的关系 1…

大数据测试基本知识

常用大数据框架结构 1.大数据测试常用到的软件工具 工具推荐&#xff0c;对于测试数据构造工具有&#xff1a;Datafaker、DbSchema、Online test data generator等&#xff1b;ETL测试工具有&#xff1a;RightData、QuerySurge等&#xff1b;数据质量检查工具&#xff1a;great…

MySQL-SQL存储过程/触发器详解(上)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…

Three.js--》实现3d地月模型展示

目录 项目搭建 初始化three.js基础代码 创建月球模型 添加地球模型 添加模型标签 今天简单实现一个three.js的小Demo&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目中才能灵活将所学知识运用起来&#xff0c;话不多说直接开始。 项目搭建 本案例还…

《离散数学》:代数系统和图论导论

一、代数系统 代数系统是数学中的一个重要概念&#xff0c;它涉及一组对象以及定义在这些对象上的运算规则。代数系统可以是抽象的&#xff0c;也可以是具体的。 在抽象代数中&#xff0c;代数系统通常由一组元素和一组操作&#xff08;或称为运算&#xff09;组成。这些操作…