3.5 队列的表示和操作的实现

news2024/11/18 15:48:25

思维导图:

 3.5.1 队列类型 

3.5.1 队列的类型定义

1. 简介

  • 队列是一种特殊的线性表,它的特性是只能在表的一端进行插入操作,而在另一端进行删除操作。
  • 通常将允许插入操作的一端称为队尾,允许删除操作的一端称为队头。

2. 抽象数据类型定义

ADT Queue

数据对象:D = {a₁, a₂, ..., an | ai∈ElemSet, i=1,2,…,n, n≥0}

数据关系:R = {<ai, aj> | ai-1, aj∈D, i=2,…,n}

约定:其中 a₁ 为队头, an 为队尾。

基本操作

  • InitQueue(&Q)

    • 操作结果:构造一个空队列Q。
  • DestroyQueue(&Q)

    • 初始条件:队列Q已存在。
    • 操作结果:销毁队列Q。
  • ClearQueue(&Q)

    • 初始条件:队列Q已存在。
    • 操作结果:将Q清为空队列。
  • QueueEmpty(Q)

    • 初始条件:队列Q已存在。
    • 操作结果:若Q为空队列,返回true;否则,返回false。
  • QueueLength(Q)

    • 初始条件:队列Q已存在。
    • 操作结果:返回Q的元素个数,即队列的长度。
  • GetHead(Q)

    • 初始条件:Q为非空队列。
    • 操作结果:返回Q的队头元素。
  • EnQueue(&Q, e)

    • 初始条件:队列Q已存在。
    • 操作结果:插入元素e为Q的新队尾元素。
  • DeQueue(&Q, &e)

    • 初始条件:Q为非空队列。
    • 操作结果:删除Q的队头元素,并用e返回其值。
  • QueueTraverse(Q)

    • 初始条件:队列Q已存在且非空。
    • 操作结果:从队头到队尾,依次对Q的每个数据元素进行访问。

3. 注意事项

  • 与栈相似,本书后文中引用的队列都基于以上定义的队列类型。
  • 队列的数据元素类型应根据应用程序的需要来定义。

我的理解:

在我看来他其实就是像计算机内存申请一段空间然后用函数限制该段内存空间的行为使其模拟成具有现实生活中队列的特点

3.5.2 循环队列——队列的顺序表示和实现

  1. 队列的存储表示

    • 顺序表示
    • 链式表示
  2. 队列的顺序存储结构

    • 与顺序栈类似
    • 使用连续的存储单元存放从队头到队尾的元素
    • 使用两个整型变量 frontrear(头指针和尾指针)来指示队头和队尾位置
  3. 队列的初始化

    • 创建空队列时,设定 front = rear = 0
    • 新增队尾元素,尾指针 rear 增1
    • 删除队头元素,头指针 front 增1
    • 在非空队中,头指针指向队头元素,尾指针指向队尾元素的下一个位置
  4. “假溢出”问题

    • 当队列没有完全满,但由于受限制的操作导致无法继续添加元素时,称为“假溢出”
    • 解决办法:将顺序队列转变为循环队列(环状空间)
  5. 循环队列的特点

    • 通过模运算实现头、尾指针在顺序表空间内的“循环”移动
    • 不能仅通过头、尾指针的值来判断队列是“满”还是“空”
  6. 判断循环队列的状态

    • 队空的条件:Q.front = Q.rear
    • 队满的条件:(Q.rear + 1) % MAXQSIZE = Q.front
  7. 处理方法

    • 少用一个元素空间:当队列空间为m时,有m-1个元素视为队满
    • 使用标志位:设置一个标志位来区分队列是“空”还是“满”
  8. 循环队列的初始化算法

    • 动态分配一个大小为 MAXQSIZE 的数组空间
    • 设置头、尾指针为0表示队列为空

概念介绍:

  • 队列的存储表示分为两种:顺序表示和链式表示。
  • 队列的顺序存储结构需要两个整型变量:front(头指针)和rear(尾指针),来分别指示队头和队尾的位置。

队列的顺序存储结构

typedef struct {
    QElemType *base;  // 存储空间的基地址
    int front;       // 头指针
    int rear;        // 尾指针
} sqQueue;
  • 初始化时: front = rear = 0。
  • 新增队尾元素: rear增1。
  • 删除队头元素: front增1。

循环队列:

  • 为解决"假溢出"问题,将顺序队列变为环状的空间。
  • 通过取模运算,使头尾指针在顺序表空间内“循环”移动。

循环队列操作:

  1. 求队列长度

    • 对于非循环队列:长度 = rear - front
    • 对于循环队列:长度 = (rear - front + MAXQSIZE) % MAXQSIZE
    int QueueLength(SqQueue Q) {
        return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
    }
    
  2. 入队操作 (EnQueue)

    • 判断队列是否满。
    • 将新元素插入队尾。
    • 队尾指针加1。
    Status EnQueue(SqQueue &Q, QElemType e) {
        if ((Q.rear + 1) % MAXQSIZE == Q.front)
            return ERROR;
        Q.base[Q.rear] = e;
        Q.rear = (Q.rear + 1) % MAXQSIZE;
        return OK;
    }
    
  3. 出队操作 (DeQueue)

    • 判断队列是否为空。
    • 保存队头元素的值。
    • 队头指针加1。
    Status DeQueue(SqQueue &Q, QElemType &e) {
        if (Q.front == Q.rear)
            return ERROR;
        e = Q.base[Q.front];
        Q.front = (Q.front + 1) % MAXQSIZE;
        return OK;
    }
    

  4. 取队头元素

    • 当队列非空时,获取队头元素。
    QElemType GetHead(SqQueue Q) {
        if (Q.front != Q.rear)
            return Q.base[Q.front];
    }
    

注意点:

  • 循环队列中,队满和队空的判断不能仅根据头尾指针是否相等来进行。
  • 常见的两种处理方法:一是少用一个元素空间;二是另设一个标志位。

小结: 循环队列通过环形结构解决了顺序队列的"假溢出"问题,并通过模运算实现头尾指针的循环移动。循环队列的各种操作相对简单,但需要注意队空和队满的判断条件。

3.5.3 链队列 —— 队列的链式表示和实现

链队列概述:

  • 链队列是采用链式存储结构实现的队列。
  • 通常链队列使用单链表来表示。一个链队列需要两个分别指示队头和队尾的指针(称为头指针和尾指针)才能唯一确定。
  • 为了操作方便,链队列添加一个头节点,并使头指针始终指向头节点。

链队列的存储结构:

typedef struct QNode{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;

typedef struct{
    QueuePtr front;  // 队头指针
    QueuePtr rear;   // 队尾指针
}LinkQueue;

操作与实现:

  1. 初始化:

    • 生成新节点作为头节点,队头和队尾指针指向此节点。
    • 头节点的指针域置空。
Status InitQueue(LinkQueue &Q){
    Q.front = Q.rear = new QNode;
    Q.front->next = NULL;
    return OK;
}
  1. 入队:

    • 为入队元素分配节点空间,用指针p指向。
    • 将新节点数据域置为e。
    • 将新节点插入到队尾。
    • 修改队尾指针为p。
    Status EnQueue(LinkQueue &Q, QElemType e){
        QNode* p = new QNode;
        p->data = e;
        p->next = NULL;
        Q.rear->next = p;
        Q.rear = p;
        return OK;
    }
    
  2. 出队:

    • 判断队列是否为空。
    • 临时保存队头元素的值,以释放空间。
    • 修改头节点的指针域,指向下一个节点。
    • 若出队的是最后一个元素,将队尾指针重新赋值指向头节点。
    • 释放原队头元素的空间。
    Status DeQueue(LinkQueue &Q, QElemType &e){
        if(Q.front == Q.rear) return ERROR;
        QNode* p = Q.front->next;
        e = p->data;
        Q.front->next = p->next;
        if(Q.rear == p) Q.rear = Q.front;
        delete p;
        return OK;
    }
    
  3. 取队头元素:

    • 如果队列非空,返回当前队头元素的值,队头指针不变。
    QElemType GetHead(LinkQueue Q){
        if(Q.front != Q.rear)
            return Q.front->next->data;
    }
    

结论:

  • 链队列避免了循环队列设定最大队列长度的限制。如果无法预估所用队列的最大长度,链队列是一个更好的选择。

 

 

 总结:

重点:

  1. 链队列的定义: 链队列使用链式结构(单链表)来实现队列的功能。与数组实现的队列不同,它没有固定的大小限制。
  2. 存储结构: 由节点组成,每个节点有一个数据域和一个指针域。使用头指针和尾指针分别指向队列的头部和尾部。
  3. 基本操作:
    • 初始化: 创建一个空队列,通常由一个头节点组成,头尾指针均指向它。
    • 入队: 在尾部添加元素。
    • 出队: 从头部删除元素。
    • 取队头元素: 获取但不删除头部元素。

难点:

  1. 头尾指针的管理: 与单链表操作略有不同,需要注意在进行入队和出队操作时正确地更新头尾指针。
  2. 空间管理: 在出队操作时,不仅要更新指针,还要释放被删除节点的内存空间。
  3. 空队列与只有一个元素的队列的处理: 当队列为空或只有一个元素时,进行出队操作需特别注意头尾指针的变化。

易错点:

  1. 不更新尾指针: 在出队操作时,如果队列只有一个元素,出队后队列为空,此时需要将尾指针重新指向头节点。
  2. 内存泄漏: 出队操作时忘记释放节点的内存空间,会导致内存泄漏。
  3. 空队列操作: 在进行出队或取队头元素操作前,没有检查队列是否为空,可能导致错误或不确定的行为。
  4. 入队操作的指针更新顺序: 先连接新节点再移动尾指针,否则可能丢失队列的后续部分。

综上所述,链队列虽然提供了灵活性,但在实现时需要注意指针操作和内存管理,以确保正确性和效率。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ArcGIS计算土地现状容积率

本文讲解在ArcGIS中,基于建筑数据和地籍边界数据,计算土地容积率。 一、容积率介绍 容积率(Plot Ratio/Floor Area Ratio/Volume Fraction)是指一个小区的地上建筑总面积与净用地面积的比率。又称建筑面积毛密度。 二、数据分析 (1)建筑数据(dwg) (2)地籍边界数据…

VsCode 只有一个标签页 编辑区只能打开一个文件

产生如图所示的问题&#xff1a; 可能是不小心取消了勾选 勾选&#xff0c;Show Tabs

软件安利——火绒安全

近年来&#xff0c;以优化、驱动、管理为目标所打造的软件屡见不鲜&#xff0c;大同小异的电脑管家相继走入了公众的视野。然而&#xff0c;在这日益急功近利的社会氛围驱动之下&#xff0c;真正坚持初心、优先考虑用户体验的电脑管家逐渐湮没在了浪潮之中。无论是鲁大师&#…

Enfocus PitStop Pro 2022(Acrobat dc增强)

Enfocus PitStop Pro 2022是一款Acrobat dc PDF编辑和校对工具&#xff0c;为Mac用户提供了强大的功能和精确的控制&#xff0c;以确保PDF文件的质量和准确性。该软件具有全面的PDF编辑功能&#xff0c;包括添加、删除或重新排列页面&#xff0c;合并和分割PDF文件&#xff0c;…

工程中Http的请求、各种回调函数的使用

文章目录 1、登录回调以及各种函数的使用1、SdoLoginClient工程中的SdoBase_Initialize3接口2、LoginClient中的Initialize接口3、ProcessResponse调用ProcessLoginResponse传递参数给回调函数使用4、ProcessLoginResponse登录响应接口的使用5、ProcessResponse调用然后根据req…

四、[mysql]索引优化-1

目录 前言一、场景举例1.联合索引第一个字段用范围查询不走索引(分情况&#xff09;2.强制走指定索引3.覆盖索引优化4.in和or在表数据量比较大的情况会走索引&#xff0c;在表记录不多的情况下会选择全表扫描5.like 后% 一般情况都会走索引(索引下推) 二、Mysql如何选择合适的索…

中移链浏览器简介

&#xff08;1&#xff09;简介 生活中&#xff0c;常用的互联网浏览器&#xff0c;是用来检索、展示以及传递Web信息资源的应用程序。用浏览器进行搜索&#xff0c;可以快速查找到目标信息。而对于区块链而言&#xff0c;也有区块链浏览器。 区块链浏览器&#xff0c;是指为用…

【案例实战】NodeJS+Vue3+MySQL实现列表查询功能

这篇文章&#xff0c;给大家带来一个列表查询的功能&#xff0c;从前端到后端的一个综合案例实战。 采用vue3作为前端开发&#xff0c;nodejs作为后端开发。 首先我们先来看一下完成的页面效果。点击分页&#xff0c;可以切换到上一页、下一页。搜索框可以进行模糊查询。 后端…

17.基干模型Swin-Transformer解读

文章目录 SWin-Transformer解读1.基础介绍关于Shifted Window based Self-Attention相对位置偏置网络整体结构和层级特征欢迎访问个人网络日志🌹🌹知行空间🌹🌹 SWin-Transformer解读 1.基础介绍 Swin-Transformer是2021年03月微软亚洲研究院提交的论文中提出的,比V…

【Linux】常见指令以及具体其使用场景

君兮_的个人主页 即使走的再远&#xff0c;也勿忘启程时的初心 C/C 游戏开发 Hello,米娜桑们&#xff0c;这里是君兮_&#xff0c;随着博主的学习&#xff0c;博主掌握的技能也越来越多&#xff0c;今天又根据最近的学习开设一个新的专栏——Linux&#xff0c;相信Linux操作系…

毛发渲染方案实现

一、毛发材质概述 以前毛发只能用离线来做 现在实时毛发逐渐可能。长毛渲染和短毛渲染采用的是不同的方案。 二、长毛类制作分析 各向异性 kajiya算法 # 三、短毛类制作分析 四、制作心得及技巧

Ansible中的playbook

目录 一、playbook简介 二、playbook的语法 三、playbook的核心组件 四、playbook的执行命令 五、vim 设定技巧 六、基本示例 一、playbook简介 1、playbook与ad-hoc相比&#xff0c;是一种完全不同的运用。 2、playbook是一种简单的配置管理系统与多机器部署系统的基础…

阿里云Apsara云栖大会2023

文章目录 2023/10/312023/11/012023/11/02彩蛋1&#xff1a;神州十六号彩蛋2&#xff1a;emm… 计算&#xff0c;为了无法计算的价值。 2023/10/31 合规性评审 2023/11/01 暂未开始 2023/11/02 暂未开始 彩蛋1&#xff1a;神州十六号 彩蛋2&#xff1a;emm…

Linux系统jdkTomcatMySQL安装以及J2EE后端接口部署

目录 一、jdk&Tomcat安装 1.1 上传安装包到服务器 1.2 解压对应工具包 1.3 配置环境变量并测试jdk安装 1.4 启动tomcat 1.5 防火墙设置 1.5.1 开启/关闭防火墙以及防火墙状态查看 1.5.2 开放防火墙端口 二、MySQL安装 2.1 卸载mariadb 2.2 在线下载MySQL安装包(…

全方位 Linux 性能调优经验总结

Part1Linux性能优化 1性能优化 性能指标 高并发和响应快对应着性能优化的两个核心指标&#xff1a;吞吐和延时 图片来自: www.ctq6.cn 应用负载角度&#xff1a;直接影响了产品终端的用户体验系统资源角度&#xff1a;资源使用率、饱和度等 性能问题的本质就是系统资源已经…

AI:46-基于深度学习的垃圾邮件识别

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

libpcap获取数据包

一、用户空间 以Linux以及TPACKET_V3为例。 调用pcap_dispatch获取数据包&#xff0c;然后回调用户传递的数据包处理函数。 read_op实际调用的是pcap_read_linux_mmap_v3 // pcap.c int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) {return (p-…

2023年【R1快开门式压力容器操作】考试题及R1快开门式压力容器操作模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 R1快开门式压力容器操作考试题是安全生产模拟考试一点通生成的&#xff0c;R1快开门式压力容器操作证模拟考试题库是根据R1快开门式压力容器操作最新版教材汇编出R1快开门式压力容器操作仿真模拟考试。2023年【R1快开…

什么是AUTOSAR ComStack,AUTOSAR架构中,CAN通信堆栈CAN Communication Stack介绍

AUTOSAR&#xff08;Automotive Open System Architecture&#xff09;ComStack指的是AUTOSAR架构中的通信堆栈。在AUTOSAR体系结构中&#xff0c;ComStack是指用于不同软件组件&#xff08;如应用软件、基础软件等&#xff09;之间进行通信的一组协议和服务。 在AUTOSAR架构中…

对于SOCKET套接字问题的若干认识

1. 首先大家应该知道Socket 编程吧 Socket套接字 分为 应用层套接字 数据链路层套接字&#xff08;也就是原始socket&#xff09; 1.流套接字(SOCK_STREAM) 流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送&#xff0c;并按顺序接…