队列,一种"公平"的数据结构
路过一家奶茶店,由于生意火爆,门口的排着长长的队伍,先排队的人先买到奶茶,然后再轮到下一个,秩序井然。有没有一种数据结构能体现”先来后到“这种顺序呢?
当然有,那就是队列。先看一下定义:队列是一种操作受限的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。只能在表的最前端删除,最后端插入,这和排队买奶茶中先给最前面的人做奶茶,新来的只能在最后面排队一样,相对“公平”。
根据定义我们可以知道,队列主要支持两种操作,一种是删除(出队dequeue)操作,另一种是插入(入队enqueue)操作,它的一个主要特点是先进先出,这一定要记住
之前我们讲过”栈“,它和队列类似,也是一种操作受限的线性表,但它是”先进后出“,与队列相反。
队列的实现
和栈一样,它可以使用数组实现(顺序队列),也可以使用链表实现(链式队列)。
顺序队列
public class QueueArray<T>
{
//存储内容的泛型数组
public T[] items;
//数组长度
private int len;
//使用头指针和尾指针辅助入队、出队操作
int head, tail = 0;
public QueueArray(int capacity)
{
items = new T[capacity];
len = capacity;
}
//入队
public bool Enqueue(T val)
{
//尾指针与数组长度相同,说明队列已满,返回false(注意,该判断存在问题)
if (tail == len)
return false;
items[tail++] = val;
return true;
}
//出队
public T Dequeue()
{
if (tail == head)
throw new Exception("Queue is empty");
return items[head++];
}
}
现在基本功能已经实现了,但仔细分析会发现,代码中的tail
和head
都只会向后移动(数量只会增加),因此tail == len
并不代表数组已满,因为数组头部的数据可能已经出队了,前面出现了许多空闲空间。如下图所示
随着不停的执行入队、出队操作,即使数组中还有空闲空间,也无法继续往队列中添加数据了。此时,需要使用数据搬移,即将队列中的元素整体搬移到数组头,如下图所示。
该操作只需要在入队并且”队列已满“的时候执行,因此我们需要修改Enqueue()的代码为
//入队
public bool Enqueue(T val)
{
if (tail == len)
{
// tail ==n && head==0,表示整个队列都占满了
if (head == 0) return false;
// 数据搬移
for (int i = head; i < tail; ++i)
{
items[i - head] = items[i];
}
// 搬移完之后重新更新head和tail
tail -= head;
}
items[tail++] = val;
return true;
}
循环队列
循环队列也是基于数组实现的,并且能够很好的解决上面当tail==n
需要数据搬移的问题(数据搬移会消耗许多性能)。
顾名思义,环形队列长得像是一个环,怎么将数组“变成”环呢?思路是当tail==n时,如果有空闲位置让tail = (tail + 1) % len
,即将尾部指针转移到数组头部来开始新的循环,这样修改最关键的就是要正确判断队空和队满的条件。下图中蓝色代表头指针,红色代表尾指针
修改入队和出队的代码
//入队
public bool Enqueue(T val)
{
//使用尾指针与头指针来判断队列是否满
if ((tail + 1) % len == head)
return false;
items[tail] = val;
tail = (tail + 1) % len;
return true;
}
//出队
public T Dequeue()
{
if (tail == head)
throw new Exception("Queue is empty");
T ans = items[head];
head = (head + 1) % len;
return ans;
}
因为判断队满使用的是(tail+1)%n=head
,所以当队列满时,tail指向的位置实际上是没有存储数据的,浪费了数组的一个存储空间。
♂ 代码虽然不多,但最好能够自己手动实现
链式队列
基于链表的实现,我们同样需要两个指针:head 指针和 tail 指针。它们分别指向链表的第一个结点和最后一个结点。如图所示,入队时,tail->next= new_node, tail = tail->next
;出队时,head = head->next
,实现起来比较简单,这里就省略了
总结
队列,一种"公平"的数据结构的更多相关文章
- 四种常见的数据结构、LinkedList、Set集合、Collection、Map总结
四种常见的数据结构: 1.堆栈结构: 先进后出的特点.(就像弹夹一样,先进去的在后进去的低下.) 2.队列结构: 先进先出的特点.(就像安检一样,先进去的先出来 ...
- 谈谈Delph中的类和对象2---类可以理解成一种特殊的数据结构、类型转换
三.类可以理解成一种特殊的数据结构 我们知道数据类型可以进行强制类型转换,类既然可以理解成一种数据类型,那么它也应该可以进行类型转换.比如下面代码为一个按钮(Button1)的单击事件 procedu ...
- Redis5种常用的数据结构
一.数据结构 五种常用的数据结构:string.hash.list.set.zse,以及三种不常用的:hyperloglog.geospatial.streams. 二.常用数据结构的使用 1.Str ...
- Python中3种内建数据结构:列表、元组和字典
Python中3种内建数据结构:列表.元组和字典 Python中有3种内建的数据结构:列表.元组和字典.参考简明Python教程 1. 列表 list是处理一组有序项目的数据结构,即你可以在一个列表中 ...
- java实现单链表、栈、队列三种数据结构
一.单链表 1.在我们数据结构中,单链表非常重要.它里面的数据元素是以结点为单位,每个结点是由数据元素的数据和下一个结点的地址组成,在java集合框架里面 LinkedList.HashMap(数组加 ...
- 3-6-汉诺塔(Hanoi Tower)问题-栈和队列-第3章-《数据结构》课本源码-严蔚敏吴伟民版
课本源码部分 第3章 栈和队列 - 汉诺塔(Hanoi Tower)问题 ——<数据结构>-严蔚敏.吴伟民版 源码使用说明 链接☛☛☛ <数据结构-C语言版> ...
- ACMer不得不会的线段树,究竟是种怎样的数据结构?
大家好,欢迎阅读周三算法数据结构专题,今天我们来聊聊一个新的数据结构,叫做线段树. 线段树这个数据结构很多人可能会有点蒙,觉得没有听说过,但是它非常非常有名,尤其是在竞赛圈,可以说是竞赛圈的必备技能. ...
- 洛谷 P1160 队列安排 Label:链表 数据结构
题目描述 一个学校里老师要将班上N个同学排成一列,同学被编号为1-N,他采取如下的方法: 1.先将1号同学安排进队列,这时队列中只有他一个人: 2.2-N号同学依次入列,编号为i的同学入列方式为:老师 ...
- ES6 一种新的数据结构--Map跟Objct的区别
var map1=new Map(); var keys={key:'val'}; map1.set(keys,'content'); ==> {Object {key: "val&q ...
随机推荐
- STP相关概念
1)桥ID(Bridge ID)=Bridge Priority+MAC 2) 端口ID(Port ID)=Port Priority+Port No 3)桥根 4)非桥根 5)根端口 6)指定端口 ...
- NOIP 模拟 $23\; \rm 赛$
题解 将所有物品分成四类,分别为两人共同喜欢的,只有一人喜欢的,没人喜欢的. 首先,先从两人共同喜欢的物品里找出 \(k\) 个,这时,就要从剩余的找出 \(\rm m-k\) 个,而且是最小的. 用 ...
- 防止XSS 攻击集成springboot
1.配置相关数据 在配置文件中配置 # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice/* # 匹 ...
- C++ 各种构造函数
c++构造函数的知识在各种c++教材上已有介绍,不过初学者往往不太注意观察和总结其中各种构造函数的特点和用法,故在此我根据自己的c++编程经验总结了一下c++中各种构造函数的特点,并附上例子,希望对初 ...
- Go错误处理正确姿势
1. panic 在什么情况下使用panic? 在程序启动的时候,如果有强依赖的服务出现故障时panic退出 在程序启动的时候,如果发现有配置明显不符合要求,可以panic退出(预防编程) 其他情况下 ...
- Go测试--性能测试分析
目录 前言 认识数据 benchstat 分析一组样本 分析两组样本 小结 前言 benchmark测试是实际项目中经常使用的性能测试方法,我们可以针对某个函数或者某个功能点增加benchmark测试 ...
- 解决移动端click事件300ms延迟的问题
方法1.部分浏览器的<meta>标签加上width=device-width就能解决. 方法2.引入fastclick.js库 <!DOCTYPE html> <html ...
- linux shell 删除满足正则表达式的文件
用find配合xargs rm find . -type f -name "to_delete_file_[a-z]_*_[0-9].jpg" | xargs rm
- uni-app 小程序从零开始的开发流程
前言 本文基于 HBuilderX 3.1.22 + 微信开发者工具 1.05.2106300为主要内容进行说明. 文档版本:1.0.0 更新时间:2021-09-03 15:32 一.准备 uni- ...
- Oracle环境配置之山路十八弯
Oracle数据库的安装 背景: 因为疫情原因,只能在家上网课,学习Oracle的时候需要安装数据库,但是!! 安装的时候出现了报错: 无法检查指定的位置是否位于 CFS 上. 出来这个基本无解,这个 ...