第3章 表、栈和队列

3.4 队列ADT

        像栈一样,队列(queue)也是表。然而,使用队列时插入在一端进行而删除则在另一端
进行。

3.4.1 队列模型

队列的基本操作是Enqueue(入队)一它是在表的末端(叫作队尾(rear))插入一个元素,还有Dequeue(出队)——它是删除(或返回)在表的开头(叫作队头(front))的元素。图3-56显示一个队列的抽象模型。

3.4.2 队列的数组实现

        如同栈的情形一样,对于队列而言,任何表的实现都是合法的。像栈一样,对于每一种操作,链表实现和数组实现都给出快速的\mathit{O(N)}运行时间。队列的链表实现简单明了,留作练习。现在我们讨论队列的数组实现。
        对于每一个队列数据结构,我们保留一个数组Queue[]以及位置Front和Rear,它们代表队列的两端。我们还要记录实际存在于队列中的元素的个数size。所有这些信息是作为一个结构的一部分,除队列例程本身外通常不会有例程直接访问它们。下图表示处于某个中间状态的一个队列。顺便指出,图中那些空白单元有着不确定的值。尤其是前三个单元含有曾经属于该队列的元素。

        为了使一个元素X入队,我们让Size和Rear增1,然后置Queue[Rear]=X。若使一个元素出队,我们置返回值为Queue[Front],Size减1,然后使Front增1。也可能有其他的策略(将在后面讨论)。现在论述错误的检测。这种实现存在一个潜在的问题。经过10次入队后队列似乎是满了,因为Rear现在是10,而下一次再入队就会是一个不存在的位置。然而,队列中也许只存在几个元素,因为若干元素可能已经出队了。像栈一样,即使在有许多操作的情况下队列也常常不是很大。
        简单的解决方法是,只要Front或Rear到达数组的尾端,它就又绕回到开头。下图显示在某些操作期间的队列情况。这叫作循环数组(circular array)实现。
        实现回绕所需要的附加代码是极小的(虽然它可能使得运行时间加倍)。如果Front或Rear增1后超越了数组规定的大小,那么其值就要重置为数组的第一个位置。

        关于队列的循环实现,有两件事情要警惕。第一,检测队列是否为空是很重要的,因为当队列为空时,一次Dequeue操作将不知不觉地返回一个不确定的值。第二,某些程序设计人员使用不同的方法来表示队列的队头和队尾。例如,有些人并不用一个单元来表示队列的大小,因为他们依靠的是基准情形,即当队列为空时Rear=Front-1。队列的大小是通过比较Rear和Front隐式算出的。这是一种非常隐秘的方法,因为存在某些特殊的情形,因此,如果你需要修改用这种方式编写的代码,那么就要特别仔细。如果队列的大小不是结构的一部分,那么若数组的大小为ASize,则当存在ASize-1个元素时队列就满了,因为只有ASize个不同的大小值可区分,而0是其中的一个。采用任意一种你喜欢的风格,但要确保你的所有例程都是一致的。由于队列的实现方法有多种选择,因此如果你不使用size字段,那就有必要在代码中插入一些注释。

        在Enqueue的次数肯定不会大于队列的大小的应用中,使用回绕是没有必要的。像栈一样,除非主调例程肯定队列非空,否则Dequeue很少执行。因此对这种操作,只要不是关键的代码,错误的调用常常被跳过。一般说来这并不是无可非议的,因为你可能得到的时间节省量是极小的。
我们通过编写某些队列的例程来结束本节,其余例程留作练习。首先,在图3-57中给出队列的声明。正如对于栈的数组实现所做的那样,我们添加一个最大大小的域。还需要提供例程CreateQueue和DisposeQueue。此外,我们还需要提供测试一个队列是否为空的例程以及构造一个空队列的例程(见图3-58和图3-59)。读者可以编写函数IsFull,用于实现判断队列是否满了的功能。注意,Rear在Front之前预初始化为1。我们将要编写的最后的操作是Enqueue例程。严格遵循上面的描述,图3-60展示了队列的数组实现。

#ifndef _Queue_h

struct QueueRecord;
typedef struct QueueRecord *Queue;

int IsEmpty(Queue Q);
int IsFull(Queue Q);
Queue CreateQueue(int MaxElements);
void DisposeQueue(Queue Q);
void MakeEmpty(Queue Q);
void Enqueue(ElementType X, Queue Q);
ElementType Front(Queue Q);
void Dequeue(Queue Q);
ElementType FrontAndDequeue(Queue Q);

#endif   /*_Queue_h*/

#define MinQueueSize (5)

struct QueueRecord
{
    int Capacity;
    int Front;
    int Rear;
    int Size;
    ElementType *Array;
};

int IsEmpty(Queue Q)
{
    return Q->Size == 0;
}

void MakeEmpty(Queue Q)
{
    Q->Size = 0;
    Q->Front = 1;
    Q->Rear = 0;
}

static int Succ(int Value, Queue Q)
{
    if (++Value == Q->Capacity)
        Value = 0;
    return Value;
}

void Enqueue(ElementType X, Queue Q)
{
    if (IsFull(Q))
        Error("Full queue");
    else
    {
        Q->Size++;
        Q->Rear = Succ(Q->Rear, Q);
        Q->Array[Q->Rear] = X;
    }
}

3.4.3 队列的应用

        有几种使用队列来提高运行效率的算法。它们当中有些可以在图论中找到,我们将在第9章讨论它们。这里,先给出某些应用队列的例子。

        当作业送交给一台行式打印机,它们就按照到达的顺序排列起来。因此,送往行式打印机的作业基本上被放到一个队列中。

        实际生活中的每次排队都(应该)是一个队列。例如,在一些售票口排列的队都是队列,因为服务的顺序是先到的先买票。

        另一个例子是关于计算机网络的。有许多种PC网络设置,其中磁盘是放在一台叫作文件服务器的机器上的。使用其他计算机的用户是按照先到先使用的原则访问文件的,因此其数据结构是一个队列。

        进一步的例子如下:

  • 当所有的接线员忙得不可开交的时候,对大公司的传呼一般都被放到一个队列中。
  • 在大学里,如果所有的终端都被占用,由于资源有限,学生们必须在一个等待表上签字。在终端上登录时间最长的学生将首先被强制离开,而等待时间最长的学生则将是下一个被允许使用终端的用户。

        处理用概率的方法计算用户排队预计等待时间、等待服务的队列能够排多长,以及其他一些诸如此类的问题将用到被称为排队论(queueing theory)的完整数学分支。问题的答案依赖于用户加入队列的频率以及一旦用户得到服务时处理服务花费的时间。这两个参数作为概率分布函数给出。在一些简单的情况下,答案可以解析算出。一种简单的例子是一条电话线有一个接线员。如果接线员忙,打来的电话就被放到一个等待队列中(这还与某个容许的最大限度有关)。这个问题在商业上很重要,因为研究表明,人们会很快挂上电话。

        如果我们有k个接线员,那么这个问题解决起来要困难得多。解析求解困难的问题往往使用模拟的方法求解。此时,我们需要使用一个队列来进行模拟。如果k很大,那么我们还需要其他一些数据结构来使得模拟更有效地进行。在第6章将会看到模拟是如何进行的。那时我们将对k的若干值进行模拟并选择能够给出合理等待时间的最小的k。

        正如栈一样,队列还有其他丰富的用途,这样一种简单的数据结构竟然能够如此重要,实在令人惊奇。

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

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

相关文章

数据结构:字典树(前缀树,Trie树),压缩字典树(Radix)

字典树Trie Tree 字典树也称前缀树,Trie树。在 Elasticsearch 的倒排索引中用的也是 Trie 树。是一种针对字符串进行维护的数据结构。 字典树是对词典的一种存储方式,这个词典中的每个“单词”就是从根节点出发一直到某一个目标节点的路径,…

YOLO5Face算法解读

论文:YOLO5Face: Why Reinventing a Face Detector 链接:https://arxiv.org/abs/2105.12931v1 机构:深圳神目科技&LinkSprite Technologies(美国) 开源代码:https://github.com/deepcam-cn/yolov5-face…

GateWay的路由与全局过滤器

1.断言工厂 我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件 例如Path/user/**是按照路径匹配,这个规则是由 org.springframework.cloud.gateway.handler.predicate.PathRoutePr…

CityEngine2023 shp数据城市与路网三维模型并导入UE5

目录 0 引言1 城市和道路数据获取1.1 常用方法1.2 OSM数据获取1.3 OSM数据格式1.3.1 所有格式1.3.2 Shapefile格式 2 实践2.1 导入数据(.shp)2.2 构建三维模型2.3 将模型导入UE5 🙋‍♂️ 作者:海码007📜 专栏&#xf…

ElasticSearch学习笔记(一)

计算机软件的学习,最重要的是举一反三,只要大胆尝试,认真验证自己的想法就能收到事办功倍的效果。在开始之前可以看看别人的教程做个快速的入门,然后去官方网站看看官方的教程,有中文教程固然是好,没有中文…

处理器中的TrustZone之安全状态

在这个主题中,我们将讨论处理器内对TrustZone的支持。其他部分则涵盖了在内存系统中的支持,以及建立在处理器和内存系统支持基础上的软件情况。 3.1 安全状态 在Arm架构中,有两个安全状态:安全状态和非安全状态。这些安全状态映射…

第一个小记录达成:第一个年费会员用户

早上看到,欸,有个用户好像充了 9.9 元,挺开心,刚刚看飞书消息,看到了这条分享给朋友,等等,是充值了 99 元,有个用户充了年费,偶买噶,开心 🫡 这是…

如何通过知识库推动企业创新?

如今的市场竞争激烈,企业创新是企业持续发展的关键之一。知识库作为企业内部的重要知识资源,对于推动企业创新具有不可替代的作用。接下来就跟大家探讨一下如何通过知识库推动企业创新。 | 一、知识库在推动企业创新中的作用 1.提高知识获取和分享效率 …

Python按要求从多个txt文本中提取指定数据

基本想法 遍历文件夹并从中找到文件名称符合我们需求的多个.txt格式文本文件,并从每一个文本文件中,找到我们需要的指定数据,最后得到所有文本文件中我们需要的数据的集合 举例 如现有名为file一个文件夹,里面含有大量的.txt格…

练习十二:利用SRAM设计一个FIFO

利用SRAM设计一个FIFO 1,任务目的2,设计要求3,FIFO接口的设计思路4,FIFO接口的测试,top.v5,FIFO接口的参考设计,fifo_interface.v6,SRAM模型,sram.v代码7,viv…

acwing算法基础之动态规划--数位统计DP、状态压缩DP、树形DP和记忆化搜索

目录 1 基础知识2 模板3 工程化 1 基础知识 暂无。。。 2 模板 暂无。。。 3 工程化 题目1:求a~b中数字0、数字1、…、数字9出现的次数。 思路:先计算1~a中每位数字出现的次数,然后计算1~b-1中每位数字出现的次数,两个相减即…

C盘分析文件大小的软件

https://sourceforge.net/projects/windirstat/ 上面是windirstat的下载链接 界面是这样的: 选择C盘或者D盘,点击OK,就可以分析了 然后就可以看到哪些占比最高,可以针对性的清理

react结合vant的Dialog实现签到弹框操作

1.需求 有时候在开发的时候,需要实现一个签到获取积分的功能,使用react怎么实现呢? 需求如下: 1.当点击“签到”按钮时,弹出签到框 2.展示签到信息: 签到天数, 对应天数签到能够获取的积分&…

JIRA 重建索引

JIRA为了增快搜索速度,为所有的问题的字段生成一个索引文件。这个索引文件存在磁盘的一个文件里面, 并且会实时更新。但是有时候某些操作后(例如增加自定义字段),需要重新建索引。 详情请见 Re-indexing after major c…

UDS 诊断报文格式

文章目录 网络层目的N_PDU 格式诊断报文的分类:单帧、多帧 网络层目的 N_PDU(network protocol data unit),即网络层协议数据单元 网络层最重要的目的就是把数据转换成符合标准的单一数据帧(符合can总线规范的),从而…

Spring Initial 脚手架国内镜像地址

官方的脚手架下载太慢了,并且现在没有了Java8的选项,所以找到国内的脚手架镜像地址,推荐给大家。 首先说官方的脚手架 官方的脚手架地址为: https://start.spring.io/ 但是可以看到,并没有了Java8的选项。 所以推荐…

手把手带你离线部署Walrus,体验极简应用交付

Walrus 0.4 已于近日发布,新版本中采用的应用模型可以让运维团队仅需配置1次,即可在多模态的基础设施及环境中运行包括应用服务及周边依赖资源在内的全套应用系统。这极大减少了运维人员的工作量,同时为研发人员屏蔽了底层基础设施的复杂度. …

Web漏洞分析-SQL注入XXE注入(上)

随着互联网的不断普及和Web应用的广泛应用,网络安全问题愈发引起广泛关注。在网络安全领域中,SQL注入和XXE注入是两个备受关注的话题,也是导致许多安全漏洞的主要原因之一。本博客将深入研究这两种常见的Web漏洞,带您探寻背后的原…

十二月四日多继承

#include <iostream>using namespace std; //定义沙发类 class Sofa { private:string *sitting; public:Sofa(){}//无参构造函数Sofa(string sitting):sitting(new string (sitting))//有参构造函数{}~Sofa() //析构函数{delete sitting;}Sofa &op…

DeepStream--测试PCB-Defect-Detection

GitHub - clintonoduor/PCB-Defect-Detection-using-Deepstream: PCB defect detection using deepstream & YoloV5我参考了了这个代码&#xff0c;作者基于YoloV5&#xff0c;训练一个电路板检测的模型&#xff0c;训练数据集来自https://robotics.pkusz.edu.cn/resources…