学习数据结构的 git 代码地址: https://gitee.com/zhangning187/js-data-structure-study

1、队列和双端队列

  队列和栈非常类似,但是使用了与 后进先出 不同的原则。双端队列是一种将栈的原则和队列的原则混合在一起的数据结构。

1.1 队列数据结构

  队列是遵循先进先出(FIFO)原则的一组有序的项。队列在尾部添加新元素,并从顶部移除元素。最新添加的元素必须排在队列的末尾。

  最常见的例子就是排队。排队打饭,排队买票等,计算机里面有排队打印等。

1.1.1 创建队列类

class Queue {
constructor() {
// 记录队列的长度,大小
this.count = 0;
// 记录队列的第一个元素
this.lowestCount = 0;
// 这里也可以使用数组,但是为了获取元素时更高效,使用对象存储元素,
// 和 Stack 非常类似,只是添加和移除元素的原则不同
this.items = {};
}
}

1.1.2 向队列添加元素

  // 向队列尾部添加项
// 这里的实现方法和 Stack 栈中的方式相同。将 count 作为items中的键对应元素作为它的值
enqueue(element) {
this.items[this.count] = element;
this.count++;
}

1.1.3 从队列移除元素

  // 移除第一项,并返回被移除的元素
dequeue() {
if (this.isEmpty()) {
return undefined;
}
const result = this.items[this.lowestCount];
// 删除最先进去的元素
delete this.items[this.lowestCount];
// 最先添加的元素位置,也要向后移动
this.lowestCount++;
return result;
}

只有 enqueue 方法和 dequeue 方法可以添加和移除元素,这样就确保了 Queue 类遵循先进先出原则。

1.1.4 查看队列头元素

  // 返回队列中第一个元素,最先被添加,也将是最先被移除的元素,队列不做任何变动,只是取值
peek() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.lowestCount];
}

1.1.5 检查队列是否为空和获取队列长度

  // 是否为空队列
isEmpty() {
return this.count === 0;
} // 队列元素个数
size() {
return this.count - this.lowestCount;
}

1.1.6 清空队列和toString方法

  // 清空队列
clear() {
this.items = {};
this.count = 0;
this.lowestCount = 0;
} toString() {
if (this.isEmpty()) {
return '';
}
let queueString = this.items[this.lowestCount];
for (let i = this.lowestCount + 1; i < this.count; i++) {
queueString += `,${this.items[i]}`;
}
return queueString;
}

1.2 双端队列数据结构

  双端队列(deque,或 double-ended queue)是一种允许我们同时从前端或后端添加或移除元素的特殊队列。

  双端队列生活中的例子,电影院、餐厅排队等。一个人刚买了票还想问一些问题,可以直接在队伍的最前面询问信息,另外,在队伍尾部的人不想排队了可以直接离开队伍。

  双端队列的一个常见应用是存储一系列的撤销操作。每当用户在软件中进行一个操作,该操作会被存在一个双端队列中(就像一个栈里面)。双端队列同时遵守了先进先出和后进先出的原则,可以说它是把队列和栈相结合的一种数据结构。

1.2.1 创建 Deque 类

class Deque {
constructor() {
this.count = 0;
this.lowestCount = 0;
this.items = {};
}
}

  双端队列是一个特殊的队列,构造函数和部分方法和队列相同,isEmpty、clear、size、toString

1.2.2 实现双端队列的方法

// 前端添加元素
addFront(element) {
if (this.isEmpty()) {// 空队列
this.addBack(element);
} else {
this.lowestCount--;
this.items[this.lowestCount] = element;
}
} // 后端添加元素
addBack(element) {
this.items[this.count] = element;
this.count++;
} // 从前端移除
removeFront() {
if (this.isEmpty()) {
return undefined;
}
const result = this.items[this.lowestCount];
// 删除最先进去的元素
delete this.items[this.lowestCount];
// 最先添加的元素位置,也要向后移动
this.lowestCount++;
return result;
} // 从后端移除
removeBack() {
if (this.isEmpty()) {
return undefined;
}
this.count--;
const result = this.items[this.count];
delete this.items[this.count];
return result;
} // 返回最前端的元素
peekFront() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.lowestCount];
} // 返回最后端的元素
peekBack() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.count - 1];
}

1.3 使用队列和双端队列解决问题

  使用队列模拟击鼓传花游戏,使用双端队列检查一个短语是否为回文。

1.3.1 循环队列--击鼓传花游戏

  队列可以修改为很多的不同队列,其中可以修改为一种循环队列。循环队列的一个例子就是击鼓传花游戏--多人围成一个圈,把花尽快地传递给旁边的人。某一刻传花停止,花在谁手里谁就退出,直到最后一个人为胜者。

// 击鼓传花
import {Queue} from './Queue.js'; // list: 人数 num: 传递次数
function hotPotato(list, num) {
const queue = new Queue();
// 淘汰的列表
const elimitatedList = []; for (let i = 0; i < list.length; i++) {
// 依次添加到队列中
queue.enqueue(list[i]);
}
while (queue.size() > 1) {
for (let i = 0; i < num; i++) {
// 队列开头移除一项添加到队尾,
// 模拟击鼓传花(如果你把花传给旁边的人,你的淘汰威胁就立即解除了)
queue.enqueue(queue.dequeue());
}
// 淘汰的放在数组中
// 一旦达到传递次数,拿着花的那个人就被淘汰了
elimitatedList.push(queue.dequeue());
}
return {
eliminated: elimitatedList,
winner: queue.dequeue()
};
} const names = ['zn1', 'zn2', 'zn3', 'zn4', 'zn5'];
const result = hotPotato(names, 7);
console.log(result);// zn1 为 winner

1.3.2 回文检查器

  回文是正反都能读通的单词、词组、数或一系列字符的序列。abba,abcd

  有不同的算法可以检查字符串是否为回文。最简单的方式是将字符串反向排列并检查它和原字符串是否相同。如果两者相同那么它就是一个回文。也可以使用栈来完成,但是利用数据结构来解决这个问题最简单的方法是使用双端队列。

// 回文检查
function palindromeChecker(aString) {
// 检查字符串是否合法
if (aString === undefined || aString === null || (aString !== null && aString.length === 0)) {
return false;
}
const deque = new Deque();
// 大小写字母都转化为小写,同时移除所有空格。
const lowerString = aString.toLocaleLowerCase().split(' ').join('');
let isEqual = true;
// 字符插入到双端队列中
for (let i = 0; i < lowerString.length; i++) {
deque.addBack(lowerString.charAt(i));
}
while (deque.size() > 1 && isEqual) {
// 最前面一个是否等于最后面一个
isEqual = deque.removeFront() === deque.removeBack();
}
return isEqual;
} console.log(1111, palindromeChecker('123321'));

1.3.3 任务队列

  当我们在浏览器中打开新标签时,就会创建一个任务队列。因为每个标签都是单线程处理所有的任务,称为事件循环。浏览器要负责多个任务,渲染HTML、执行 JavaScript 代码、处理用户交互(用户输入、鼠标点击等)、执行和处理异步请求。

-----------磨刀不误砍柴工、加油!!!

JavaScript 数据结构与算法2(队列和双端队列)的更多相关文章

  1. PHP双向队列,双端队列代码

    <?php /**  * User: jifei  * Date: 2013-07-30  * Time: 23:12 */ /**  * PHP实现双向队列,双端队列  * 双端队列(dequ ...

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

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

  3. python 下的数据结构与算法---4:线形数据结构,栈,队列,双端队列,列表

    目录: 前言 1:栈 1.1:栈的实现 1.2:栈的应用: 1.2.1:检验数学表达式的括号匹配 1.2.2:将十进制数转化为任意进制 1.2.3:后置表达式的生成及其计算 2:队列 2.1:队列的实 ...

  4. Java 模拟队列(一般队列、双端队列、优先级队列)

    队列: 先进先出,处理类似排队的问题,先排的.先处理,后排的等前面的处理完了,再处理 对于插入和移除操作的时间复杂度都为O(1).从后面插入,从前面移除 双端队列: 即在队列两端都能够insert和r ...

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

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

  6. 双端队列-deque【集vector与list于一身的牺牲内存换功能完善】

    看到双端队列(deque)了,书上是这样说的:除了栈和队列外还有一种限定性数据结构是双端队列:双端队列是限定插入和删除操作在表的两端进行的线性表:尽管双端队列看起来似乎比栈和队列更灵活,但实际上在应用 ...

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

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

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

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

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

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

随机推荐

  1. 为什么 Thread 类的 sleep()和 yield ()方法是静态的?

    Thread 类的 sleep()和 yield()方法将在当前正在执行的线程上运行.所以在其他处于等待状态的线程上调用这些方法是没有意义的.这就是为什么这些方法是静态的.它们可以在当前正在执行的线程 ...

  2. Javascript 占位符替换

    String.prototype.format=function(){ if(arguments.length===0){ return String(this); } let reg=/(\{\d\ ...

  3. kafka 的高可用机制是什么?

    这个问题比较系统,回答出 kafka 的系统特点,leader 和 follower 的关系,消息 读写的顺序即可.

  4. 谷歌浏览器postman插件安装,亲测可用

    将谷歌浏览器进入扩展程序,将crx文件拖入即可. https://pan.baidu.com/s/1rIEe9RSby5EgTkygSx_dDA 百度云链接: https://pan.baidu.co ...

  5. Netty学习摘记 —— 再谈ChannelHandler和ChannelPipeline

    本文参考 本篇文章是对<Netty In Action>一书第六章"ChannelHandler和ChannelPipeline",主要内容为ChannelHandle ...

  6. SringBoot之yaml语法

    ------------恢复内容开始------------ SpringBoot之yaml语法 1.配置文件 官方配置文档太多了,根本记不住! 怎么办呐-->了解原理 SpringBoot使用 ...

  7. (stm32学习总结)—SPI-FLASH 实验

    SPI总线 SPI 简介 SPI 的全称是"Serial Peripheral Interface",意为串行外围接口,是Motorola 首先在其 MC68HCXX 系列处理器上 ...

  8. 汽车最强大脑ECU和单片机是什么关系

    先上图一张,据说这是某个F1赛车的动力总成ECU. 定睛一看,这不就是两个英飞凌的单片机的合体嘛. ECU的定义 ECU原来指的是engine control unit,即发动机控制单元,特指电喷发动 ...

  9. simulink仿真过程

    Simulink求解器 Simulink仿真过程 Simulink 模型的执行分几个阶段进行.首先进行的是初始化阶段,在此阶段,Simulink 将库块合并到模型中来,确定传送宽度.数据类型和采样时间 ...

  10. 5_终值定理和稳态误差_Final Value Theorem & Steady State Error