学习数据结构的 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. mac-变量

    去除每次都要source : 加入:

  2. 学习ELK日志平台(四)

    一:需求及基础: 场景: 1.开发人员不能登录线上服务器查看详细日志 2.各个系统都有日志,日志数据分散难以查找 3.日志数据量大,查询速度慢,或者数据不够实时 4.一个调用会涉及到多个系统,难以在这 ...

  3. vue3在组件上使用v-model

    v-model用于在元素上创建双向数据绑定,负责监听用户输入事件来更新数据. v-model应用于输入框 <input v-model="searchText" /> ...

  4. Netty学习摘记 —— 心跳机制 / 基于分隔符和长度的协议

    本文参考 本篇文章是对<Netty In Action>一书第十一章"预置的ChannelHandler和编解码器"的学习摘记,主要内容为通过 SSL/TLS 保护 N ...

  5. 论Hello World 有多少种输出方法:

    论Hello World 有多少种输出方法: C: printf("Hello Word!"); C++: cout<<"Hello Word!"; ...

  6. react开发教程(六)React与DOM

    ReactDOM findeDOMNode 语法:DOMElement findDOMNode(ReactComponent component)描述:获取改组件实例相对应的DOM节点 案例: imp ...

  7. js压缩图片到2m以下

    用的canvas.这个问题测试妹子反馈了好几次bug,解决了好多次,虽然用了比较僵硬的办法,但总算最终解决了. 因为php的同事说,页面上的图片要直接调用七牛的接口上传到七牛,所以后端那边不能处理,必 ...

  8. 一个命令完成[打包+同步七牛cdn+上传服务器]

    webpack+gulp+qshell+npm-scripts实现一个命令完成[打包+同步cdn+上传服务器] 说明 由于我们用的七牛云存储,所以cdn也是走的七牛,所以并不适用于其他的cdn,但是思 ...

  9. 【uniapp 开发】字典工具类 ObjectUtil

    {__/} ( • - •) /つ寿司 你要不要? {__/} ( • - •) /つ草莓 你要不要? {__/} ( • - •) /つ披萨 你要不要? {__/} ( • - •) /つ桃子 你要 ...

  10. 主线程中的Looper.loop()为什么不会造成ANR

    引子: 正如我们所知,在android中如果主线程中进行耗时操作会引发ANR(Application Not Responding)异常. 造成ANR的原因一般有两种: 当前的事件没有机会得到处理(即 ...