http://data.biancheng.net/view/300.html
栈和队列不要混淆,栈是一端开口、另一端封口,元素入栈和出栈遵循“先进后出”原则;
队列是两端都开口,但元素只能从一端进,从另一端出,且进出队列遵循“先进先出”的原则。
定义
类似于现实中排队时的队列(队尾进,队头出),插入元素的一端称为队尾,删除(取出)元素的一端称为队头。分别对应于入队和出队操作。
队列的特点
1、元素只能从队列的一端进入,从另一端出去
通常,我们将元素进入队列的一端称为“队尾”,进入队列的过程称为“入队”;将元素从队列中出去的一端称为“队头”,出队列的过程称为“出队”。
2、队列中各个元素的进出必须遵循“先进先出”的原则,即最先入队的元素必须最先出队。
3、队列也不能直接访问位于中间的数据,必须通过出队操作将目标数据变成首位后才能访问。
队列的实际应用
解决 CPU 资源的竞争问题
对于一台计算机来说,CPU 通常只有 1 个,是非常重要的资源。如果在很短的时间内,有多个程序向操作系统申请使用 CPU,就会出现竞争 CPU 资源的现象。不同的操作系统,解决这一问题的方法是不一样的,有一种方法就用到了队列这种存储结构。
假设在某段时间里,有 A、B、C 三个程序向操作系统申请 CPU 资源,操作系统会根据它们的申请次序,将它们排成一个队列。根据“先进先出”原则,最先进队列的程序出队列,并获得 CPU 的使用权。待该程序执行完或者使用 CPU 一段时间后,操作系统会将 CPU 资源分配给下一个出队的程序,以此类推。如果该程序在获得 CPU 资源的时间段内没有执行完,则只能重新入队,等待操作系统再次将 CPU 资源分配给它。
顺序队列
实现
我们采用 C 语言中的数组实现顺序表。既然用顺序表模拟实现队列,必然要先定义一个足够大的数组。不仅如此,为了遵守队列中数据从 “队尾进,队头出” 且 “先进先出” 的规则,还需要定义两个变量(top 和 rear)分别记录队头和队尾的具体位置,
缺点
在元素不断入队、出队的过程中,顺序队列会整体向顺序表的尾部移动。整个实现方案存在的缺陷是:
- 顺序队列前面的空闲空间无法再被使用,会造成空间浪费;
- 当顺序队列移动至顺序表尾部时,即便顺序表中有空闲空间,新元素也无法成功入队,我们习惯将这种现象称为“假溢出”。
循环队列
顺序队列的 “假溢出” 问题:队列的存储空间未满,却发生了溢出。比如尾指针现在虽然已经指向了最后一个位置的下一位置,但是之前队头也删除了一些元素,那么头指针经历若干次的加1之后,留出了很多空位置,但是顺序队列还在傻乎乎的以为再有元素入队就溢出呢!肯定不合理。故循环队列诞生!
所以解决"假溢出"的办法就是后面满了,就再从头开始,也就是头尾相接的循环。我们把队列的这种头尾相接的顺序存储结构称为循环队列。将新元素插入到第一个位置上,入队和出队仍按先进先出的原则进行,操作效率高,空间利用率高。
缺点
判空的问题,因为仅凭 front = rear 不能判定循环队列是空还是满。
链式队列
队列
使用链表形式来实现队列。
使用单向链表来实现链式队列,链式队列中存储front和rear即可。
为了方便实现,链式队列中的front表示链表的头节点,而front的next才表示队头
在链式队列中,不需要考虑队列是否已满,只要内存足够就可以一直分配空间。而当front和rear都指向头节点的时候,则表示此时队列为空。
入队时移动rear指向最后一个元素即可。
出队时,不需要移动front指针,只需将其next指针指向下一个next元素即可。q->front->next = q->front->next->next; 但是需要考虑一种特殊情况,即当队列中只剩下一个元素时,还需要使rear指针重新指向头节点。
顺序队列和链式队列的比较
顺序队列是用数组实现的,首指针在出队的时候移动,尾指针在入队的时候移动,需要考虑队列为空和队列为满的两种情况
链式队列是用链表实现的,首指针不移动始终指向头节点,尾指针在入队的时候移动,只考虑队列为空的情况(不用考虑满是因为链表长度在程序运行过程中可以不断增加,只要存储空间够malloc就能申请内存空间来存放节点)
本文介绍了数据结构中的队列,包括队列的基本概念、特点和实际应用。详细讲解了顺序队列和链式队列的实现方式,以及各自的优缺点,如顺序队列的空间浪费和循环队列解决的假溢出问题。同时提到了链式队列在处理队列为空和队列操作上的灵活性。

1035

被折叠的 条评论
为什么被折叠?



