ImageVerifierCode 换一换
格式:DOCX , 页数:18 ,大小:28.54KB ,
资源ID:26163251      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/26163251.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(队列的定义精.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

队列的定义精.docx

1、队列的定义精三、队列 1 队列的定义 队列(Queue)简称队,它也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。我们把进行插入的一端称作队尾(rear),进行删除的一端称作队首(front)。向队列中插入新元素称为进队或入队,新元素进队后就成为新的队尾元素;从队列中删除元素称为离队或出队,元素离队后,其后继元素就成为队首元素。由于队列的插入和删除操作分别是在各自的一端进行的,每个元素必然按照进入的次序离队,所以又把队列称为先进先出表(First In First Out, 简称FIFO)。 在日常生活中,人们为购物或等车时所排的队就是一个队列,新来购物或等

2、车的人接到队尾(即进队),站在队首的人购到物品或上车后离开(即出队),当最后一人离队后,则队列为空。 例如,假定有a,b,c,d四个元素依次进队,则得到的队列为(a,b,c,d),其中字符a为队首元素,字符d为队尾元素。若从此队中删除一个元素,则字符a出队,字符b成为新的队首元素,此队列变为(b,c,d);若接着向该队列插入一个字符e,则e成为新的队尾元素,此队列变为(b,c,d,e);若接着做三次删除操作,则队列变为(e),此时只有一个元素e,它既是队首元素又是队尾元素,当它被删除后队列变为空。 2. 队列的存储结构 队列的存储结构同线性表和栈一样,既可以采用顺序结构,也可以采用链接结构。

3、(1) 队列的顺序存储结构 队列的顺序存储结构需要使用一个数组和两个整型变量来实现,利用数组来顺序存储队列中的所有元素,利用两个整型变量来分别存储队首元素和队尾元素的下标位置,分别称它们为队首指针和队尾指针。假定存储队列的数组用queueQueueMaxSize表示,队首和队尾指针分别用front和rear表示,则元素类型为ElemType的队列的顺序存储类型可定义为: ElemType queueQueueMaxSize; int front, rear; 其中QueueMaxSize为一个整型全局常量,需事先通过const语句定义,由它确定顺序队列(即顺序存储的队列)的最大长度,即最多能够

4、存储的元素个数。当然,队列的顺序存储空间也可以采用动态分配,此时用于决定最大长度的量可以为全局常量,也可以为全局或局部变量。如在一个函数的函数体中使用下面语句能够为一个队列分配长度为n的数组空间,该数组名仍用queue表示。 ElemType* queue=new ElemTypen; 队列的顺序存储类型同样可以用一个记录类型来表示,假定记录类型名为Queue,则该类型定义为: struct Queue ElemType queueQueueMaxSize; int front, rear; ; 假定一个队列的当前状态如图4-10(a)所示,此时已经有a,b,c三个元素相继出栈(为了同队列中的

5、元素相区别,把它们分别括了起来),队首指针front的值为3,指向的队首元素为d,队尾指针的值为7,指向的队尾元素为h;若接着插入一个新元素i,则队列的当前状态如图4-10(b)所示;若再接着删除一个元素,则变为图4-10(c)所示。 0 1 2 3 4 5 6 7 8 QueueMaxSize-1 (a) (b) (c) d e f g h front rear (a) 0 1 2 3 4 5 6 7 8 QueueMaxSize-1 (a) (b) (c) d e f g h i front rear (b) 0 1 2 3 4 5 6 7 8 QueueMaxSize-1 (a) (b)

6、 (c) (d) e f g h i front rear (c) 图4-10 顺序队列的插入和删除操作示意图 每次向队列插入一个元素,需要首先使队首指针后移一个位置,然后再向这个位置写入新元素。当队尾指针指向数组空间的最后一个位置QueueMaxSize-1时,若队首元素的前面仍存在空闲的位置,则表明队列未占满整个数组空间,下一个存储位置应是下标为0的空闲位置,因此,首先要使队尾指针指向下标为0的位置,然后再向该位置写入新元素。通过语句rear=(rear+1)%QueueMaxSize可使存储队列的整个数组空间变为首尾相接的一个环(称此为循环队列),当rear指向最后一个存储位置时,下一个

7、所求的位置自动为数组空间的开始位置(即下标为0的位置)。 同对线性表和栈的插入一样,每次在进行队列插入前,也要判断队列是否已满(即数组空间是否已被用完),若是则停止插入,终止程序运行,否则可向队列中插入新元素。若队尾指针的下一个位置(采用(rear+1)%QueueMaxSize计算出来)恰是队首指针front所指的位置,则表明队列已满,可知判断队满的条件是(rear+1)%QueueMaxSize=front。从另一方面看,若队首指针和队尾指针已经指向了同一个位置,则表明队列中只有一个元素,当删除该元素后,队列为空,队尾指针不变,而队首指针指向了下一个位置,此时队尾指针的下一个位置正好也是队

8、首指针所指的位置,由此可知,当条件(rear+1)%QueueMaxSize=front成立时,可能是队满的情况,也可能是队空的情况。为了区别这两种情况,可设置一个标记,当进行插入操作后,置该标记为1,当进行删除操作后,置该标记为0。在标记为1的情况下,上述条件成立则表明队列已满,在标记为0的情况下,上述条件成立则表明队列为空。为了省去设置一个标记的麻烦,通常采用的处理方法是:让front指针不是指向队首元素的位置,而是指向它的前一个位置,当上述条件成立时队列必然为满,当队首指针等于队尾指针时队列为空,此时整个数组空间只能利用QueueMaxSize-1个存储位置,而不是QueueMaxSiz

9、e个存储位置。 在顺序队列中进行插入和删除时,不需要比较和移动任何元素,只需要修改队尾和队首指针,并向队尾写入元素或从队首取出元素,所以其时间复杂性为O(1)。 (2) 队列的链接存储结构 队列的链接存储结构也是通过由结点构成的单链表实现的,此时只允许在单链表的表头进行删除和在单链表的表尾进行插入,因此它需要使用两个指针:队首指针front和队尾指针rear。用front指向队首(即表头)结点的存储位置,用rear指向队尾(即表尾)结点的存储位置。用于存储队列的单链表简称链接队列或链队。假定链队中的结点类型仍采用第二章定义的LNode结点类型,那么队首和队尾指针为LNode*指针类型。若把一个

10、链队的队首指针和队尾指针定义在一个记录类型中,并假定该记录类型用标识符LinkQueue表示,则定义如下: struct LinkQueue LNode* front; LNode* rear; ; 其中LNode结点类型重写如下: struct LNode ElemType data; LNode* next; ; 设一个队列为(a,b,c),则对应的链接存储结构如图4-12(a)所示,当向该链队插入一个元素d后,对应如图4-12(b)所示,当接着从中删除队首元素a后,对应如图4-12(c)所示。 图4-12 链队的插入和删除操作示意图 对链队的插入和删除操作同样不需要比较和移动元素,只需要

11、修改个别相关指针和进行结点的动态分配或回收操作,所以其时间复杂度为O(1)。另外,使用链队不存在队满的问题,因为它使用的结点是动态分配的,只要内存中动态存储区仍有可用空间,就可以得到一个新结点,使之插入到链队中;链队也可能为空,此时front和rear指针均为空。 3. 队列的抽象数据类型 队列的抽象数据类型中的数据部分为具有ElemType元素类型的一个队列,它可以采用任一种存储结构实现;操作部分包括元素进队、出队、读取队首元素、检查队列是否为空等。下面给出队列的抽象数据类型的具体定义:ADT QUEUE is Data: 采用顺序或链接方式存储的栈,假定其存储类型 用QueueType标识

12、符表示。 Operation: void InitQueue(QueueType& Q); /初始化队列Q,即置Q为空 void ClearQueue(QueueType& Q); /清除队列Q中的所有元素,使之成为一个空队 int QueueEmpty(QueueType& Q); /判断Q是否为空,若是则返回1,否则返回0 ElemType QFront(QueueType& Q); /返回队首元素,但不改变队列状态 void QInsert(QueueType& Q, const ElemType& item); /将新元素item的值插入到队尾 ElemType QDelete(Que

13、ueType& Q); /从队列Q中删除队首元素并返回之 int QueueFull(Queue& Q) /若队列已满则返回1,否则返回0,此函数为顺序 /存储的队列所特有 end QUEUE 假定队列q的元素类型为整型int,下面给出调用上述操作的一些例子。 (1) InitQueue(q); /把队列置空 (2) QInsert(q,20); /元素20进队 (3) int x=5; QInsert(q,10*x); /元素10*x的值50进队 (4) coutQFront(q)endl; /输出队首元素20 (5) QDelete(q); /删除队首元素20 (6) cout(x=QDe

14、lete(q)endl; /删除队首元素50,把它赋给x同时输出 (7) x=QueueEmpty(q); /因队列为空,返回1并赋给x (8) while(!QueueEmpty(q) coutQDelete(q)” ”; /依次输出队 /列q中的所有元素,因q已经为空,所以不会得到任何输出 4. 队列运算的实现 同线性表和栈一样,队列运算(操作)的具体实现取决于队列的存储结构,存储结构不同,其算法描述也不同。下面分别给出队列的运算在顺序和链接两种存储结构上的实现的算法。 (a) 队列运算在顺序存储结构上的实现 假定采用Queue记录类型的对象Q来表示顺序存储的队列,则在Q上进行各种队列运算

15、的算法描述如下: (1) 初始化队列 void InitQueue(Queue& Q) /把队首和队尾指针置为同一下标值0,表示队空 Q.front=Q.rear=0; (2) 把一个队列清除为空 void ClearQueue(Queue& Q) /对于顺序队列,此算法与初始化队列的算法相同 Q.front=Q.rear=0; (3) 检查一个队列是否为空 int QueueEmpty(Queue& Q) /当队首与队尾指针相同时表示队空,返回1,否则返回0 return Q.front=Q.rear; (4) 读取队首元素 ElemType QFront(Queue& Q) /返回队首元素

16、,但不改变队列状态 if(Q.front=Q.rear) /队列为空时退出程序运行 cerrQueue is empty!endl; exit(1); return Q.queue(Q.front+1)%QueueMaxSize; /队首元素是队首指针的下一个位置中的元素 (5) 向队列插入元素 void QInsert(Queue& Q, const ElemType& item) /将新元素item的值插入到队尾 int k=(Q.rear+1)%QueueMaxSize; /求出队尾的下一个位置 if(k=Q.front) /若对列已满则终止程序运行 cerrQueue overflow

17、!endl; exit(1); Q.rear=k; /修改队尾指针使之指向下一个位置 Q.queuek=item; /item的值被赋给新的队尾位置 (6) 从队列中删除元素 ElemType QDelete(Queue& Q) /删除队首元素并返回之 if(Q.front=Q.rear) /若队列为空则终止运行 cerrQueue is empty!next; delete p; p=HQ.front; /此循环结束后,所有结点被清除,队首指针变为空 HQ.rear=NULL; /置队尾指针为空 (3) 检查链队是否为空 int QueueEmpty(LinkQueue& HQ) /若链队为

18、空则返回1,否则返回0 return HQ.front=NULL; /判断队首或队尾任一个指针是否为空即可 (4) 读取队首元素 ElemType QFront(LinkQueue& HQ) /读取链队中的队首元素 if(HQ.front=NULL) /若链队为空则终止执行 cerrLinked queue is empty!data; /返回队首元素 (5) 向链队中插入一个元素 void QInsert(LinkQueue& HQ, const ElemType& item) /使新元素item的值插入链队 LNode* newptr=new LNode; /得到一个由newptr指针所指

19、向的新结点 if(newptr=NULL) /若内存动态存储空间用完则终止程序 cerrMemory allocation failare!data=item; /把item的值赋给新结点的值域 newptr-next=NULL; /把新结点的指针域置空 if(HQ.rear=NULL) HQ.front=HQ.rear=newptr; /若链队为空,则新结点既是队首结点又是队尾结点 else HQ.rear=HQ.rear-next=newptr; /依次修改队尾结点的 /指针域和队尾指针使之指向新的队尾结点 (6) 从队列中删除一个元素 ElemType QDelete(LinkQueue

20、& HQ) /从链队中删除队首元素 if(HQ.front=NULL) /若链队为空则终止运行 cerrLinked queue is empty!data; /暂存队首元素以便返回 LNode* p=HQ.front; /暂存队首指针以便回收队首结点 HQ.front=p-next; /使队首指针指向下一个结点 if(HQ.front=NULL) HQ.rear=NULL; /若链队变为空,则需同时使队尾指针变为空 delete p; /回收原队首结点 return temp; /返回被删除的队首元素 5. 使用队列的程序举例 程序1: #include #include const int

21、 QueueMaxSize=6; typedef int ElemType; struct Queue ElemType queueQueueMaxSize; int front, rear; ; #includequeue.h /该头文件保存着对顺序队列进行各种操作的算法 void main() Queue q; InitQueue(q); for(int i=0; i6; i+) int x=rand()%100; int y=rand()%100; if(!QueueFull(q) QInsert(q,x); coutx 进队, ; if(!QueueFull(q) QInsert(q,

22、y); couty 进队; coutendl; coutQDelete(q) 出队endl; coutendl; while(!QueueEmpty(q) coutQDelete(q) 出队endl; 此程序使用一个长度为6的顺序队列,利用此队列保存由计算机产生的随机数。主函数中的for循环体共执行6次,每次执行时首先产生出两个100以内的随机整数,接着在队列未满时入队,然后进行一次出栈操作,在主函数的最后使队列中的所有元素依次出队。该程序的运行结果为: 41 进队, 67 进队 41 出队 34 进队, 0 进队 67 出队 69 进队, 24 进队 34 出队 78 进队, 58 进队 0

23、 出队 62 进队, 69 出队 5 进队, 24 出队 78 出队 58 出队 62 出队 5 出队 程序2: #include #include typedef int ElemType; struct LNode ElemType data; LNode* next; ; struct LinkQueue LNode* front; LNode* rear; ; #includelinkqueue.h /此头文件保存着对链队的各种操作的算法 void main() LinkQueue q1,q2; InitQueue(q1); InitQueue(q2); for(int i=0; i2

24、0; i+) int x=rand()%100; coutx ; if(x%2=1) QInsert(q1,x); /用q1链队存放奇数 else QInsert(q2,x); /用q2链队存放偶数 coutendl; while(!QueueEmpty(q1)&!QueueEmpty(q2) /每一行输出一个奇数和一个偶数,直到任一队列空为止 coutQDelete(q1) QDelete(q2)endl; 此程序使用了两个链队q1和q2,用来分别存储由计算机随机产生的20个100以内的奇数和偶数,然后每行输出q1和q2中的一个值,即奇数和偶数配对输出,直到任一队列为空时止。该程序的运行结果

25、为: 41 67 34 0 69 24 78 58 62 64 5 45 81 27 61 91 95 42 27 36 41 34 67 0 69 24 5 78 45 58 81 62 27 64 61 42 91 36 6. 队列的应用简介 在后面的章节中将会看到队列在具体算法中的应用,这里仅从两个方面来简述队列在计算机科学领域所起的作用。第一个方面是解决主机与外部设备之间速度不匹配的问题,第二个方面是解决由多用户引起的资源竞争问题。对于第一个方面,仅以主机和打印机之间速度不匹配的问题为例作一下简要说明。主机输出数据给打印机打印,输出数据的速度比打印数据的速度要快得多,若直接把输出的数据

26、送给打印机打印,由于速度不匹配,显然是不行的。所以解决的方法是设置一个打印数据缓冲区,主机把要打印输出的数据依次写入到这个缓冲区中,写满后就暂停输出,转去做其它的事情;打印机就从缓冲区中按照先进先出的原则依次取出数据并打印,打印完后再向主机发出请求,主机接到请求后再向缓冲区写入打印数据,这样做既保证了打印数据的正确,又使主机提高了效率。由此可见,打印数据缓冲区中所存储的数据就是一个队列。对于第二个方面,CPU(即中央处理器,它包括运算器和控制器)资源的竞争就是一个典型的例子。在一个带有多终端的计算机系统上,有多个用户需要CPU各自运行自己的程序,它们分别通过各自终端向操作系统提出占用CPU的请求,操作系统通常按照每个请求在时间上的先后顺序,把它们排成一个队列,每次把CPU分配给队首请求的用户使用,当相应的程序运行结束或用完规定的时间间隔后,则令其出队,再把CPU分配给新的队首请求的用户使用,这样既满足了每个用户的请求,又使CPU能够正常运行。关于队列在这两个方面应用的详细情况将会在操作系统课程中讨论。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1