前言

队列和栈非常类似,前面已经讲过了栈的实现与用法,现在我们来说说队列。

队列介绍

队列遵循FIFO(First In First Out,先进先出)原则的一组有序的项。

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

队列有顺序队列,还有其他修改版本的队列,比如:优先队列、循环队列。

顺序队列

顺序队列是队列的顺序存储结构,它是运算受限制的顺序表(线性表)。建立顺序队列结构必须为其静态分配或动态申请一片连续的存储空间,并设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置,如图所示。

生活中,各种排队现象。例如:排队买票,新来的人,排在队尾,相当于添加操作。队头的人先买票,买完票离开队列,相当于删除操作。而添加的操作却只能在队列的尾部进行,因此新来的人就只能排在队列的最后。

创建队列

队列中的元素,可以使用链表存储,也可以使用数组存储。我们使用数组来存储队列中的元素。


/** * 队列 * 我们使用数组来存储队列中的元素 * *=====队列的入队、出队示意图======== * * 出队 ----------------- 入队 * <--- A1,A2,A3,...,An <--- * ----------------- * *================================ */ export default class Queue { constructor() { this.items = []; } /** * 向队尾添加一个(或多个)新的元素 * @param {*} element 新元素 */ enqueue(element) { this.items.push(element) } /** * 移除队列的第一(即排在队列最前面的)项,并返回被移除的元素 */ dequeue() { // 根据队列的先进先出原则,使用shift方法 // shift方法会从数组中移除存储在索引为0的元素 return this.items.shift() } /** * 返回队列中的第一个元素--最先被添加,也将是最先被移除的元素。 * 队列不做任何变动(不移除元素,只返回元素信息) */
front() { return this.items[0] } /** * 清除队列中的所有元素 */ clear() { this.items = [] } /** * 如果队列中不包含任何元素,返回true,否则返回false */ isEmpty() { return this.items.length === 0 } /** * 返回队列包含的元素个数,与数组length属性类似 */ size() { return this.items.length } /** * 队列内容字符串化 */ toString() { return this.items.toString() } }

顺序队列应用

打印机,有一个打印队列,谁先进入队列,谁就先打印。


/** * 打印队列的内容 * @param {Array} queueArr 需要打印的数组 */ function print(queueArr) { let queue = new Queue() let s = '' /** * 检查参数类型是否为数组 */ if (queueArr instanceof Array) { /** * 将需要打印内容添加到队列 */ for (let i = 0; i < queueArr.length; i++) { queue.enqueue(queueArr[i]) } /** * 将队头的数据取出 */ while (!queue.isEmpty()) { s += queue.dequeue() + ', ' } s = s.substr(0, s.length - 2) } return s; }

更多内容请查看源码

优先队列

队列有顺序队列,还有其他修改版本的队列,比如:循环队列、优先队列

优先队列是顺序队列的修改版本,元素的添加和移除是基于优先级的。一个现实例子是,在银行排队办业务的顺序。VIP客户的优先级要高于普通客户的。另一个例子是医院的急诊科候诊室。医生会优先处理病情比较严重的患者。通常,护士会鉴别分类,根据患者病情的严重程度放号。

实现一个优先队列,有两种选项:

  1. 设置优先级,然后在正确的位置添加元素。(优先添加,正常出队)

  2. 用入列操作添加元素,然后按照优先级移除它们。(正常添加,优先出队)

优先队列的实现

我们在这里将会使用第一种方式,在正确的位置添加元素,因此可以对它们使用默认的出列操作。

queueElement.js 文件


// queueElement.js /** * 优先队列中的元素,包含元素和优先级 */ export default class QueueElement { /** * * @param {*} element 队列的元素 * @param {*} priority 优先级 */ constructor(element, priority) { this.element = element this.priority = priority } }

priorityQueue.js文件


// priorityQueue.js import QueueElement from "./queueElement"; /** * 最小优先队列 */ export default class PriorityQueue { constructor() { this.items = [] } /** * 在正确的位置添加元素 * @param {*} element 要添加的元素 * @param {Int32Array} priority 优先级 */ enqueue(element, priority) { let queueElement = new QueueElement(element, priority) let added = false for (let i = 0; i < this.items.length; i++) { // 当找到一个比要添加的元素的优先级更高的项时,将新元素插入到它之前。 if (queueElement.priority < this.items[i].priority) { this.items.splice(i, 0, queueElement) // 插入新元素 added = true break // 终止队列循环 } } // 当需要添加的元素优先级大于队列中的任何一个元素的时候,把该元素添加到队尾。 if (!added) { this.items.push(queueElement) } } /** * 打印队列中的元素(包含优先级) */ print() { for (let i = 0; i < this.items.length; i++) { console.log(`${i + 1} - ${this.items[i].element} - ${this.items[i].priority}`) } } /** * 移除队列的第一(即排在队列最前面的)项,并返回被移除的元素 */ dequeue() { // 根据队列的先进先出原则,使用shift方法 // shift方法会从数组中移除存储在索引为0的元素 return this.items.shift() } /** * 返回队列中的第一个元素--最先被添加,也将是最先被移除的元素。 * 队列不做任何变动(不移除元素,只返回元素信息) */ front() { return this.items[0] } /** * 清除队列中的所有元素 */ clear() { this.items = [] } /** * 如果队列中不包含任何元素,返回true,否则返回false */ isEmpty() { return this.items.length === 0 } /** * 返回队列包含的元素个数,与数组length属性类似 */ size() { return this.items.length } /** * 队列内容字符串化 */ toString() { return this.items.toString() } }

优先队列的应用


let priorityQueue = new PriorityQueue() priorityQueue.enqueue('wei', 2) priorityQueue.enqueue('qin', 3) priorityQueue.enqueue('world', 1) priorityQueue.enqueue('china', 1) priorityQueue.print()

输出结果


1 - wei - 1 2 - world - 1 3 - china - 1 4 - qin - 2

查看源码详情

循环队列

循环队列的一个例子就是击鼓传花的游戏。在这个游戏中,孩子们围成一个圆圈,把花尽快的传递给旁边的人。某一时刻传花停止,这个时候花在谁手里,谁就退出圆圈结束游戏。重复这个过程,直到只剩一个孩子(胜者)。

另一个类似的案例是,约瑟夫环问题

下面,我们以击鼓传花游戏来分析。

import Queue from "./queue-array";

export default class CircleQueue {

  constructor() {}

  hotPotato(nameList, num) {
// 利用顺序队列创建的队列,来完成循环队列
let queue = new Queue() for (let i = 0; i < nameList.length; i++) {
queue.enqueue(nameList[i])
} let eliminated = '';
while (queue.size() > 1) {
// 此过程将队列变成循环队列
for (let i = 0; i < num; i++) {
queue.enqueue(queue.dequeue());
}
eliminated = queue.dequeue();
console.log(eliminated + '在击鼓传花游戏中被淘汰')
}
// 返回最后胜利者
return queue.dequeue() } }

查看源码详情

以上所有的队列,都是在数组结构的基础上创建和应用的。

[完]

Javascript数据结构与算法--队列(顺序队列、优先队列、循环队列)的实现与用法的更多相关文章

  1. 为什么我要放弃javaScript数据结构与算法(第四章)—— 队列

    有两种结构类似于数组,但在添加和删除元素时更加可控,它们就是栈和队列. 第四章 队列 队列数据结构 队列是遵循FIFO(First In First Out,先进先出,也称为先来先服务)原则的一组有序 ...

  2. javascript 数据结构和算法读书笔记 > 第五章 队列

    队列是一种列表,但是它只能够在队尾插入元素,在队首删除元素.队列用于存储按照顺序排列的数据,先进先出.而栈则是后入栈的元素反而被优先处理. 实际中一般被应用在进程池.排队操作上面. 1. 队列的操作 ...

  3. JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)

    前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...

  4. javascript数据结构与算法---队列

    javascript数据结构与算法---队列 队列是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素.队列用于存储按顺序排列的数据,先进先出,这点和栈不一样(后入先出).在栈中,最后入栈的元素 ...

  5. 重读《学习JavaScript数据结构与算法-第三版》- 第5章 队列

    定场诗 马瘦毛长蹄子肥,儿子偷爹不算贼,瞎大爷娶个瞎大奶奶,老两口过了多半辈,谁也没看见谁! 前言 本章为重读<学习JavaScript数据结构与算法-第三版>的系列文章,主要讲述队列数据 ...

  6. JavaScript数据结构与算法-队列练习

    队列的实现 // 队列类 function Deque () { this.dataStore = []; this.enqueueFront = enqueueFront; this.enqueue ...

  7. javascript数据结构与算法---检索算法(顺序查找、最大最小值、自组织查询)

    javascript数据结构与算法---检索算法(顺序查找.最大最小值.自组织查询) 一.顺序查找法 /* * 顺序查找法 * * 顺序查找法只要从列表的第一个元素开始循环,然后逐个与要查找的数据进行 ...

  8. 前端开发周报: CSS 布局方式方式与JavaScript数据结构和算法

    前端开发周报:CSS 布局方式与JavaScript动画库 1.常见 CSS 布局方式详见: 一些常见的 CSS 布局方式梳理,涉及 Flex 布局.Grid 布局.圣杯布局.双飞翼布局等.http: ...

  9. 为什么我要放弃javaScript数据结构与算法(第九章)—— 图

    本章中,将学习另外一种非线性数据结构--图.这是学习的最后一种数据结构,后面将学习排序和搜索算法. 第九章 图 图的相关术语 图是网络结构的抽象模型.图是一组由边连接的节点(或顶点).学习图是重要的, ...

随机推荐

  1. python 私有方法

    最近了解到python私有方法的来由: Python中默认的成员函数,成员变量都是公开的(public),而且python中没有类似public,private等关键词来修饰成员函数,成员变量. 在p ...

  2. $refs的用法及作用

    获取DOM元素,一般用document.querySelector获取这个dom节点,然后在获取input的值 但是用ref绑定之后,就不需要在获取dom节点了,直接在上面的input上绑定input ...

  3. Java JPS找不到正在执行的java进程 jps cannot see running java process

    最近磁盘进展,把临时目录/tmp给全删了,结果发现jps的输出为空,找不到正在运行的jvm进程. 但是新建的进程没有问题,能够正常查看: [root@node-master ~]# ps -e|gre ...

  4. FPGA

    FPGA(Field-Programmable Gate Array),即现场可编程门阵列,它是在PAL.GAL.CPLD等可编程器件的基础上进一步发展的产物.它是作为专用集成电路(ASIC)领域中的 ...

  5. 【SQL学习笔记】一、select语句

    SQL有别于其他的编程语言的一点在于首先处理的并不是写在第一行的语句(select),而是from字句. 为了更详细的了解select语句的每个部分,举例如下: 该语句返回的结果是下订单超过4次的女顾 ...

  6. HDU-1171 Big Event in HDU(生成函数/背包dp)

    题意 给出物品种类,物品单价,每种物品的数量,尽可能把其分成价值相等的两部分. 思路 背包的思路显然是用一半总价值当作背包容量. 生成函数则是构造形如$1+x^{w[i]}+x^{2*w[i]}+.. ...

  7. Power BI行级别安全性(数据权限管理)

    自从PowerBI 的DAX 函数 支持username() 或 userprincipalname()的函数后,我们就可以在Power BI中实现根据用户的行级数据权限的控制. username() ...

  8. Beta答辩总结

    组员名单 短学号 姓名 备注 409 后敬甲 组长 301 蔡文斌 315 黄靖茹 423 刘浩 317 黄泽 328 卢泽明 617 葛亮 344 张杰 348 朱跃安 链接汇总 组长博客:后敬甲 ...

  9. 【easy】Number of Segments in a String 字符串中的分段数量

    以空格为分隔符,判断一个string可以被分成几部分. 注意几种情况:(1)全都是空格 (2)空字符串(3)结尾有空格 思路: 只要统计出单词的数量即可.那么我们的做法是遍历字符串,遇到空格直接跳过, ...

  10. Centos7安装JDK+部署Tomcat8

    Centos7下JDK+Tomcat的部署: 1.安装JDK 1.1 通过以下命令获得java JDK列表 yum -y list java* 1.2 通过yum安装JDK yum -y instal ...