前言

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

队列介绍

队列遵循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. 大规模使用 Apache Kafka 的20个最佳实践

    必读 | 大规模使用 Apache Kafka 的20个最佳实践 配图来源:书籍<深入理解Kafka> Apache Kafka是一款流行的分布式数据流平台,它已经广泛地被诸如New Re ...

  2. 处理 Vue 单页面应用 SEO

    由于在vue单页应用中title只设定在入口文件index.html,如果切换路由,title怎么更换? 在路由router中设置meta: { path:'/chooseBrand', compon ...

  3. (二叉树 BFS) leetcode 107. Binary Tree Level Order Traversal II

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

  4. 常见的数据扩充(data augmentation)方法

    G~L~M~R~S 一.data augmentation 常见的数据扩充(data augmentation)方法:文中图片均来自吴恩达教授的deeplearning.ai课程 1.Mirrorin ...

  5. 关于IsDeleted,Islock,State类型Bit,char(1),tinyint的探讨

    做IsDeleted,Islock,State时,字段的数据类型选择一般有三种Bit,char,tinyint,大于2个字节的类型我们暂时不考虑,这里以mssql为例. 数据大小​: Bit,char ...

  6. python 正则指北之我的总结

    本文经本人搜索网络加上个人理解整理而成,如有侵权,请告知,会立即删除! 正则引擎大体上可分为不同的两类:DFA和NFA,而NFA又基本上可以分为传统型NFA和POSIX NFA. DFA Determ ...

  7. 深入理解Java自带的线程池和缓冲队列

    前言 线程池是什么 线程池的概念是初始化线程池时在池中创建空闲的线程,一但有工作任务,可直接使用线程池中的线程进行执行工作任务,任务执行完成后又返回线程池中成为空闲线程.使用线程池可以减少线程的创建和 ...

  8. oldboy s21day15模块装饰器及其他应用

    #!/usr/bin/env python# -*- coding:utf-8 -*- # 1.sys.path.append("/root/mods")的作用?"&qu ...

  9. [Reinforcement Learning] Value Function Approximation

    为什么需要值函数近似? 之前我们提到过各种计算值函数的方法,比如对于 MDP 已知的问题可以使用 Bellman 期望方程求得值函数:对于 MDP 未知的情况,可以通过 MC 以及 TD 方法来获得值 ...

  10. NPOI读取excel表,如果有公式取出的是公式,想要取数字怎么办?

    public static DataTable Import(string strFileName) { DataTable dt = new DataTable(); HSSFWorkbook hs ...