数据结构14:队列(Queue),“先进先出”的数据结构
队列是线性表的一种,在操作数据元素时,和栈一样,有自己的规则:使用队列存取数据元素时,数据元素只能从表的一端进入队列,另一端出队列,如图1。

称进入队列的一端为“队尾”;出队列的一端为“队头”。数据元素全部由队尾陆续进队列,由队头陆续出队列。
队列的先进先出原则
队列从一端存入数据,另一端调取数据的原则称为“先进先出”原则。(first in first out,简称“FIFO”)
图1中,根据队列的先进先出原则,(a1,a2,a3,…,an)中,由于 a1 最先从队尾进入队列,所以可以最先从队头出队列,对于 a2 来说,只有 a1 出队之后,a2 才能出队。
类似于日常生活中排队买票,先排队(入队列),等自己前面的人逐个买完票,逐个出队列之后,才轮到你买票。买完之后,你也出队列。先进入队列的人先买票并先出队列(不存在插队)。
队列的实现方式
队列的实现同样有两种方式:顺序存储和链式存储。
队列的顺序表示和实现
使用顺序存储结构表示队列时,首先申请足够大的内存空间建立一个数组,除此之外,为了满足队列从队尾存入数据元素,从队头删除数据元素,还需要定义两个指针分别作为头指针和尾指针。
当有数据元素进入队列时,将数据元素存放到队尾指针指向的位置,然后队尾指针增加 1;当删除对头元素(即使想删除的是队列中的元素,也必须从队头开始一个个的删除)时,只需要移动头指针的位置就可以了。
顺序表示是在数组中操作数据元素,由于数组本身有下标,所以队列的头指针和尾指针可以用数组下标来代替,既实现了目的,又简化了程序。
例如,将队列(1,2,3,4)依次入队,然后依次出队并输出。
代码实现:
#include <stdio.h>
int enQueue(int *a, int rear, int data)
{
a[rear] = data;
rear++;
return rear;
}
void deQueue(int *a, int front, int rear)
{
//如果 front==rear,表示队列为空
while (front != rear)
{
printf("%d", a[front]);
front++;
}
}
int main()
{
int a[];
int front, rear;
//设置队头指针和队尾指针,当队列中没有元素时,队头和队尾指向同一块地址
front = rear = ;
//入队
rear = enQueue(a, rear, );
rear = enQueue(a, rear, );
rear = enQueue(a, rear, );
rear = enQueue(a, rear, );
//出队
deQueue(a, front, rear);
return ;
}
顺序存储存在的问题
当使用线性表的顺序表示实现队列时,由于按照先进先出的原则,队列的队尾一直不断的添加数据元素,队头不断的删除数据元素。由于数组申请的空间有限,到某一时间点,就会出现 rear 队列尾指针到了数组的最后一个存储位置,如果继续存储,由于 rear 指针无法后移,就会出错。
数组真的满了吗?队头由于删除元素,front 后移, front 前边还会有可以使用的空间。所以为了充分利用这部分空间,可以考虑使用下面这种方式。
顺序存储的升级版
使用数组存取数据元素时,可以将数组申请的空间想象成首尾连接的环状空间使用。例如,在申请的内存空间大小为 5 的情况下,将数字 1-6 进队后再出队(普通方式中 6 是无法进队的):
代码实现:
#include <stdio.h>
#define max 5
int enQueue(int *a, int front, int rear, int data)
{
//循环队列中,如果尾指针和头指针重合,证明数组存放的数据已满
if ((rear+)%max == front)
{
printf("空间已满");
return rear;
}
a[rear%max] = data;
rear++;
return rear;
}
int deQueue(int *a, int front, int rear)
{
//如果front==rear,表示队列为空
if(front == rear)
{
printf("队列为空");
return front;
}
printf("%d", a[front]);
front = (front+)%max;
return front;
}
int main()
{
int a[max];
int front, rear;
//设置队头指针和队尾指针,当队列中没有元素时,队头和队尾指向同一块地址
front = rear = ;
//入队
rear = enQueue(a, front, rear, );
rear = enQueue(a, front, rear, );
rear = enQueue(a, front, rear, );
rear = enQueue(a, front, rear, );
//出队
front = deQueue(a, front, rear); rear = enQueue(a, front, rear, ); front = deQueue(a, front, rear);
rear = enQueue(a, front, rear, );
front = deQueue(a, front, rear);
front=deQueue(a, front, rear);
front=deQueue(a, front, rear);
front=deQueue(a, front, rear);
return ;
}
运行结果:
123456
在使用循环队列判断数组是否已满时,出现下面情况:
- 当队列为空时,队列的头指针等于队列的尾指针
- 当数组满员时,队列的头指针等于队列的尾指针
要将空队列和队列满的情况区分开,办法是:牺牲掉数组中的一个存储空间,判断数组满员的条件是:尾指针的下一个位置和头指针相遇,就说明数组满了。
队列的链式表示和实现(简称为“链队列”)
队列的链式存储是在链表的基础上,按照“先进先出”的原则操作数据元素。
例如,将队列(1,2,3,4)依次入队,然后再依次出队。
代码实现:
#include <stdio.h>
#include <stdlib.h>
typedef struct QNode
{
int data;
struct QNode *next;
}QNode;
QNode *initQueue()
{
QNode *queue = (QNode*)malloc(sizeof(QNode));
queue->next = NULL;
return queue;
}
QNode *enQueue(QNode *rear, int data)
{
QNode *enElem = (QNode*)malloc(sizeof(QNode));
enElem->data = data;
enElem->next = NULL;
//使用尾插法向链队列中添加数据元素
rear->next = enElem;
rear = enElem;
return rear;
}
void DeQueue(QNode *front, QNode *rear)
{
if (front->next == NULL)
{
printf("队列为空");
return ;
}
QNode *p = front->next;
printf("%d", p->data);
front->next = p->next;
if (rear == p)
{
rear = front;
}
free(p);
}
int main()
{
QNode *queue, *front, *rear;
queue = front = rear = initQueue(); //创建头结点
//向链队列中添加结点,使用尾插法添加的同时,队尾指针需要指向链表的最后一个元素
rear = enQueue(rear, );
rear = enQueue(rear, );
rear = enQueue(rear, );
rear = enQueue(rear, );
//入队完成,所有数据元素开始出队列
DeQueue(front, rear);
DeQueue(front, rear);
DeQueue(front, rear);
DeQueue(front, rear);
DeQueue(front, rear);
return ;
}
运行结果:
1234队列为空
使用链队列的心得体会
在使用链队列时,最简便的方法就是链表的表头一端表示队列的队头,表的另一端表示队列的队尾,这样的设置会使程序更简单。
另外需要注意的是,在删除队列中数据元素的时候,每次都需要判断队列是否为空,这就需要寻找一个判断队列为空的条件:如果头结点的指针域为NULL,说明队列为空;如果队头和队尾指针都指向头结点,说明队列为空。(二选一)
使用链队列解决问题时,要避免“野指针”的出现:
.当删除最后一个数据元素时,由于一贯地认为数据元素出队列只跟队头指针有关系,会忽略队尾指针。
.当链队列中只剩有一个数据元素时,队尾指针指向的就是这个数据元素,被删除后,队尾指针指向的内存空间被释放,还有可能给别的程序使用。
这时候,队尾指针如果不进行重定义,就会变成“野指针”。
数据结构14:队列(Queue),“先进先出”的数据结构的更多相关文章
- Python与数据结构[2] -> 队列/Queue[0] -> 数组队列的 Python 实现
队列 / Queue 数组队列 数组队列是队列基于数组的一种实现,其实现类似于数组栈,是一种FIFO的线性数据结构. Queue: <--| 1 | 2 | 3 | 4 | 5 |<-- ...
- 算法与数据结构基础 - 队列(Queue)
队列基础 队列具有“先进先出”的特点,用这个特点我们可以用它来处理时间序列相关或先后次序相关的问题,例如 LeetCode题目 933. Number of Recent Calls,时间复杂度O(1 ...
- 数据结构:队列queue 函数push() pop size empty front back
队列queue: push() pop() size() empty() front() back() push() 队列中由于是先进先出,push即在队尾插入一个元素,如:可以输出:Hello W ...
- 数据结构之队列(queue)
队列介绍 1.队列是一个有序列表,可以用数组或是链表来实现. 2.遵循先入先出的原则.即:先存入队列的数据,要先取出.后存入的要后取出. 应用场景 比如某某银行叫号系统: 数组模拟队列 队列本身是有序 ...
- [ACM训练] 算法初级 之 数据结构 之 栈stack+队列queue (基础+进阶+POJ 1338+2442+1442)
再次面对像栈和队列这样的相当基础的数据结构的学习,应该从多个方面,多维度去学习. 首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个 ...
- 【Java数据结构学习笔记之二】Java数据结构与算法之队列(Queue)实现
本篇是数据结构与算法的第三篇,本篇我们将来了解一下知识点: 队列的抽象数据类型 顺序队列的设计与实现 链式队列的设计与实现 队列应用的简单举例 优先队列的设置与实现双链表实现 队列的抽象数据类型 ...
- 【Java数据结构学习笔记之三】Java数据结构与算法之队列(Queue)实现
本篇是数据结构与算法的第三篇,本篇我们将来了解一下知识点: 队列的抽象数据类型 顺序队列的设计与实现 链式队列的设计与实现 队列应用的简单举例 优先队列的设置与实现双链表实现 队列的抽象数据类型 ...
- 数据结构 -- 队列Queue
一.队列简介 定义 队列(queue)在计算机科学中,是一种先进先出的线性表. 它只允许在表的前端进行删除操作,而在表的后端进行插入操作.进行插入操作的端称为队尾,进行删除操作的端称为队头.队列中没有 ...
- 数据结构之队列(Queue)
1,队列的定义 队列:是一种先进先出的数据结构,如下图所示,现进去的数据在队列前面(front),先出队列,后进入队列的数据在后面(rear),后出队列. 队列常用操作: q=Queue() #创建队 ...
随机推荐
- C# IL中间代码注入实现切面编程
背景及现状:之前分享的那篇“面向切面编程–渲染监控日志记录方案”中提供了利用RealProxy作为代理类来生成代理的面向切面的编程方法,那个方法可以实现面向切面编程进行日志记录,现在渲染主程序也是采用 ...
- 将Windows下磁盘出现黑色为分配区域变成绿色区域
在windows下不知什么原因, 有一块磁盘空间F盘就变成了黑色为分配区域. 黑色区域无法用来安装双系统, 网上查阅资料后, 找到了如何将他重新变回绿色区域的2个方法(方法二是自己无意操作成功的). ...
- CSS——display
display的主要属性: 1.none: 不显示: 不保留其在页面中的位置,即相当于html文档中没有这个元素: visible:hidden虽然也不显示:但依然保存着他的位置和大小. 2.bloc ...
- 安卓读取SD卡的容量
在开发中,我们经常会用到SD卡,那么在对SD卡进行读写的时候,我们经常需要判断SD卡的剩余容量是否足够.因此,这次我们来写写获取SD卡容量的程序. 该注意的地方,我都在程序里面有注明了.看程序基本就懂 ...
- css的relative与absolute(一)
relative与absolute是position的两个值,本文对这两个值得关系进行了一个小实验 实验一: 首先定义了两个div元素,代码如下所示: <!doctype html> &l ...
- springboot中单元测试
测试service: 测试api:
- Luogu 2375 [NOI2014]动物园
字胡串什么的一直不太会,感觉这题…还蛮本质的 考虑暴力求解:num[i]相当于从一直跳nxt,如果nxt[j] * 2 <= i 那么就累加答案 其实这是一个树的结构,也就是说跳到一个结点满足条 ...
- vue 之 指令系统介绍
浏览目录 条件渲染 class 与style绑定 事件处理 指令系统介绍 所谓指令系统,大家可以联想咱们的cmd命令行工具,只要我输入一条正确的指令,系统就开始干活了. 在vue中,指令系统,设置一些 ...
- Entity Framework Tutorial Basics(38):Explicit Loading
Explicit Loading with DBContext Even with lazy loading disabled, it is still possible to lazily load ...
- 形式化验证工具(PAT)羊车门代码学习
首先介绍一下PAT工具,下图是PAT工具的图标 PAT工具全称是Process Analysis Toolkit,可以做一些简单的验证. 今天我们分析一下例子里面的Monty Hall Problem ...