重读《学习JavaScript数据结构与算法-第三版》- 第5章 队列
定场诗
马瘦毛长蹄子肥,儿子偷爹不算贼,瞎大爷娶个瞎大奶奶,老两口过了多半辈,谁也没看见谁!
前言
本章为重读《学习JavaScript数据结构与算法-第三版》的系列文章,主要讲述队列数据结构、双端队列数据结构以及队列相关应用。
队列
队列是遵循先进先出(FIFO)原则的一组有序的项。队列在尾部添加元素,并从顶部移除元素。最新添加的元素必须排在队列的末尾。现实中常见的队列就是排队,计算机科学中,常见的例子是打印队列,如文档按顺序打印,第一个发送到打印队列的文档优先被打印。
实现队列
/**
* class Queue 队列类
* 特点:先进先出
*/
class Queue {
construcor () {
// 存储数据
this.items = {}
// 队列头部元素索引
this.lowestCount = 0
// 队列尾部元素索引
this.count = 0
}
/**
* enqueue() 添加元素到队列 - 先进先出
* @param {*} element 添加到队列的元素
*/
enqueue (elemenet) {
this.items[this.count] = element
this.count++
}
/**
* dequeue() 移除队列头部元素 - 先进先出
* @returns {*} result 返回头部元素
*/
dequeue () {
if (this.isEmpty()) {
return undefined
}
let result = this.items[this.lowestCount]
delete this.items[this.lowestCount]
this.lowestCount++
return result
}
/**
* peek() 返回队列头部元素
* @returns {*}
*/
peek () {
if (this.isEmpty()) {
return undefined
}
return this.items[this.lowestCount]
}
/**
* isEmpty() 判断队列是否为空
* @returns {Boolean}
*/
isEmpty () {
return this.count === this.lowestCount
}
/**
* size() 队列长度
* @returns {Number}
*/
size () {
return this.count - this.lowestCount
}
/**
* clear() 清空队列
*/
clear () {
this.items = {}
this.count = 0
this.lowestCount = 0
}
/**
* toString() 返回队列的字符串结构
* @returns {String}
*/
toString () {
if (this.isEmpty()) {
return ''
}
let queueStr = `${this.items[this.lowestCount]}`
for (let i = this.lowestCount + 1; i < this.count; i++) {
queueStr = `${queueStr},${this.items[i]}`
}
return queueStr
}
}
使用队列
// 实例化队列
const queue = new Queue()
// 判断队列是否为空
console.log(queue.isEmpty()) // true
// 向队列中添加元素
queue.enqueue('John')
queue.enqueue('Jack')
console.log(queue.toString()) // John,Jack
queue.enqueue('Camila')
console.log(queue.toString()) // John,Jack
console.log(queue.size()) // 3
console.log(queue.isEmpty()) // false
以上操作示意图:
console.log(queue.dequeue()) // John
console.log(queue.dequeue()) // Jack
console.log(queue.toString()) // Camila
以上操作示意图
双端队列
双端队列是一种允许我们同时从前端和后端添加和移除元素的特殊队列。在计算机科学中双端队列常见应用是存储一系列的撤销操作。
- 当用户在软件中进行了操作时,该操作从尾部进入双端队列;
- 当用户点击撤销按钮时,从双端队列的尾部移除;
- 当队列中的操作达到预定义的一定数量后,最先存入的操作会被移除(头部移除)
双端队列同时遵守了先进先出和后进先出的原则
实现双端队列
/**
* class Deque 双端队列
* 特点:支持先进先出、后进先出
*/
class Deque {
constructor () {
this.items = {}
this.count = 0
this.lowestCount = 0
}
/**
* addFront() 从头部插入
* @param {*} element 待插入队首的元素
*/
addFront (element) {
this.lowestCount--
this.items[this.lowestCount] = element
}
/**
* addBack() 从尾部插入
* @param {*} element 待插入队尾的元素
*/
addBack (element) {
this.items[this.count] = element
this.count++
}
/**
* removeFront() 队首移除元素
* @returns {*}
*/
removeFront () {
if (this.isEmpty()) {
return undefined
}
let result = this.items[this.lowestCount]
delete this.items[this.lowestCount]
this.lowestCount++
return result
}
/**
* removeBack() 队尾移除元素
* @returns {*}
*/
removeBack () {
if (this.isEmpty()) {
return undefined
}
let result = this.items[this.count -1]
delete this.items[this.count - 1]
this.count--
return result
}
/**
* isEmpty() 判断是否为空
* @returns {Boolean} 是否为空
*/
isEmpty () {
return this.count === this.lowestCount
}
/**
* size() 返回队列的长度
* @returns {Number} 队列的长度
*/
size () {
return this.count - this.lowestCount
}
/**
* clear() 清空队列
*/
clear () {
this.items = {}
this.count = 0
this.lowestCount = 0
}
/**
* peekFront() 获取队首元素
* @returns {*}
*/
peekFront () {
if (this.isEmpty()) {
return undefined
}
return this.items[this.lowestCount]
}
/**
* peekBack() 获取队尾元素
* @returns {*}
*/
peekBack () {
if (this.isEmpty()) {
return undefined
}
return this.items[this.count - 1]
}
/**
* toString() 展示字符串形式
* @returns {*}
*/
toString () {
if (this.isEmpty()) {
return ''
}
let str = `${this.items[this.lowestCount]}`
for (let i = this.lowestCount + 1; i < this.count; i++) {
str = `${str},${this.items[i]}`
}
return str
}
}
使用双端队列
const deque = new Deque()
console.log(deque.isEmpty()) // true
deque.addFront('宋江')
deque.addFront('晁盖')
deque.addBack('吴用')
console.log(deque.size()) // 3
console.log(deque.toString()) // 晁盖,宋江,吴用
console.log(deque.removeFront()) // 晁盖
console.log(deque.removeBack()) // 吴用
console.log(deque.toString()) // 宋江
console.log(deque.size()) // 1
实战应用
循环队列 - 模拟击鼓传花游戏
规则:
- 使用队列模拟击鼓传花
- 当执行一定的约定次数(每次都随机一个数)时,花在谁手里,谁被淘汰
- 重复执行游戏,直到剩下最后一人,为胜利者
/**
* hotPotato() 模拟击鼓传花游戏
* @param {Array} elementList 需传入的参与游戏的人员列表
* @returns {Object} 返回信息:淘汰者和胜利者
*/
function hotPotato (elementList) {
// 实例化队列,将元素放入队列
let queue = new Queue()
elementList.forEach((value) => {
queue.enqueue(value)
})
// 淘汰的人
let elimitatedList = []
// 开始游戏,直到队列中剩余1人
while (queue.size() > 1) {
// 为了让游戏更加有意思,每次停止的位置进行随机处理
for (let i = 0; i < Math.floor(Math.random() * 10); i++) {
// 取出头部第一个元素,然后执行插入
queue.enqueue(queue.dequeue())
}
// 此时拥有花的人,淘汰
elimitatedList.push(queue.dequeue())
}
// 返回
return {
elimitatedList,
winner: queue.dequeue()
}
}
let elementList = [
'孙悟空',
'唐僧',
'如来佛祖',
'玉帝',
'王母'
]
// 调用函数,传入elementList,同时约定第6次时,拥有花的小伙伴被淘汰...
let result = hotPotato(elementList, 6)
console.log(result)
result.elimitatedList.forEach((name) => {
console.log(`${name}被淘汰了...`)
})
console.log(`${result.winner}胜利了...`)
以上代码运行效果 -- 展示其中一次的执行结果
{ elimitatedList: [ '唐僧', '王母', '孙悟空', '如来佛祖' ], winner: '玉帝' }
唐僧被淘汰了...
王母被淘汰了...
孙悟空被淘汰了...
如来佛祖被淘汰了...
玉帝胜利了...
回文检查器
什么是回文?
回文是正反都能读通的单词、词组、数或一系列字符的序列,例如:aba、madam
那如何实现回文检查器呢?
1. 使用反转排列字符串与原字符串进行比较
/**
* palindromeChecker() 回文检查器
* @param {String} str 待检查的字符串
* @returns {Boolean}
*/
function palindromeChecker (str) {
// 检测是否是合法字符串
if (str === undefined || str === null || (str !== null && str.length === 0)) {
return false
}
return str.split('').reverse().join('') === str
}
let str = 'aba'
console.log(palindromeChecker(str)) // true
2. 使用数据结构-栈实现回文检查器
/**
* palindromeChecker() 回文检查器
* @param {String} str 待检查的字符串
* @returns {Boolean}
*/
function palindromeChecker (str) {
// 检测是否是合法字符串
if (str === undefined || str === null || (str !== null && str.length === 0)) {
return false
}
let stack = new Stack()
// 分割字符串
for (let i = 0; i < str.length; i++) {
stack.push(str[i])
}
let reverseStr = ''
while (!stack.isEmpty()) {
reverseStr += stack.pop()
}
return str === reverseStr
}
let str = 'aba'
console.log(palindromeChecker(str)) // true
此处栈
class Stack
的实现,请参考上一篇文章:重读《学习JavaScript数据结构与算法-第三版》- 第4章 栈
3. 使用双端队列实现回文检查器
/**
* palindromeChecker() 回文检查器
* @param {String} str 待检查的字符串
* @returns {Boolean}
*/
function palindromeChecker (str) {
// 检测是否是合法字符串
if (str === undefined || str === null || (str !== null && str.length === 0)) {
return false
}
let deque = new Deque()
for (let i = 0; i < str.length; i++) {
deque.addBack(str[i])
}
// 设置是否是回文的标记
let isEqual = true
while (deque.size() > 1 && isEqual) {
// 取出收尾进行比较
let front = deque.peekFront()
let back = deque.peekBack()
if (front !== back) {
isEqual = false
}
}
return isEqual
}
let str = 'abc'
console.log(palindromeChecker(str)) // false
str = 'aba'
console.log(palindromeChecker(str)) // true
后记
以上就是胡哥今天给大家分享的内容,喜欢的小伙伴记得收藏
、转发
、点击右下角按钮在看
,推荐给更多小伙伴呦,欢迎多多留言交流...
胡哥有话说,一个有技术,有情怀的胡哥!京东开放平台首席前端攻城狮。与你一起聊聊大前端,分享前端系统架构,框架实现原理,最新最高效的技术实践!
长按扫码关注,更帅更漂亮呦!关注胡哥有话说公众号,可与胡哥继续深入交流呦!
重读《学习JavaScript数据结构与算法-第三版》- 第5章 队列的更多相关文章
- 重读《学习JavaScript数据结构与算法-第三版》- 第4章 栈
定场诗 金山竹影几千秋,云索高飞水自流: 万里长江飘玉带,一轮银月滚金球. 远自湖北三千里,近到江南十六州: 美景一时观不透,天缘有分画中游. 前言 本章是重读<学习JavaScript数据结构 ...
- 重读《学习JavaScript数据结构与算法-第三版》-第2章 ECMAScript与TypeScript概述
定场诗 八月中秋白露,路上行人凄凉: 小桥流水桂花香,日夜千思万想. 心中不得宁静,清早览罢文章, 十年寒苦在书房,方显才高志广. 前言 洛伊安妮·格罗纳女士所著的<学习JavaScript数据 ...
- 重读《学习JavaScript数据结构与算法-第三版》- 第6章 链表(一)
定场诗 伤情最是晚凉天,憔悴厮人不堪言: 邀酒摧肠三杯醉.寻香惊梦五更寒. 钗头凤斜卿有泪,荼蘼花了我无缘: 小楼寂寞新雨月.也难如钩也难圆. 前言 本章为重读<学习JavaScript数据结构 ...
- 重读《学习JavaScript数据结构与算法-第三版》- 第3章 数组(一)
定场诗 大将生来胆气豪,腰横秋水雁翎刀. 风吹鼍鼓山河动,电闪旌旗日月高. 天上麒麟原有种,穴中蝼蚁岂能逃. 太平待诏归来日,朕与先生解战袍. 此处应该有掌声... 前言 读<学习JavaScr ...
- 学习JavaScript数据结构与算法 (二)
学习JavaScript数据结构与算法 的笔记 包含第四章队列, 第五章链表 本人所有文章首发在博客园: http://www.cnblogs.com/zhangrunhao/ 04队列 实现基本队列 ...
- 学习JavaScript数据结构与算法 (一)
学习JavaScript数据结构与算法 的笔记, 包含一二三章 01基础 循环 斐波那契数列 var fibonaci = [1,1] for (var i = 2; i< 20;i++) { ...
- 学习JavaScript数据结构与算法---前端进阶系列
学习建议 1.视频学习---认知 建议:在中国慕课上找"数据结构"相关的视频教程.中国大学MOOC 推荐清华大学.北京大学.浙江大学的教程,可先试看,然后根据自身的情况选择视频进行 ...
- 学习Javascript数据结构与算法(第2版)笔记(1)
第 1 章 JavaScript简介 使用 Node.js 搭建 Web 服务器 npm install http-server -g http-server JavaScript 的类型有数字.字符 ...
- 学习JavaScript数据结构与算法 2/15
第一章 JavaScript简介 js不同于C/C++,C#,JAVA,不是强类型语言. 通常,代码质量可以用全局变量和函数的数量来考量(数量越多越糟).因此,尽可能避免使用全局变量. JS数据类型 ...
随机推荐
- 微信小程序开发--组件(3)
一.radio <radio-group class="radio-group" bindchange="radioChange"> <lab ...
- 洛谷P2880 [USACO07JAN]平衡的阵容Balanced Lineup 题解
题目链接: https://www.luogu.org/problemnew/show/P2880 分析: ST表实现即可,一个最大值数组和最小值数组同时维护 代码: #include<cstd ...
- C#4.0新增功能02 命名实参和可选实参
连载目录 [已更新最新开发文章,点击查看详细] C# 4 介绍命名实参和可选实参. 通过命名实参,你可以为特定形参指定实参,方法是将实参与该形参的名称关联,而不是与形参在形参列表中的位置关联. ...
- C#3.0新增功能09 LINQ 基础01 语言集成查询
连载目录 [已更新最新开发文章,点击查看详细] 语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# 语言的技术统称. 数据查询历来都表示为简单的字符串,没有编译时类型检查或 Inte ...
- css 图片裁剪显示
用object-fit:cover object-fit属性详解 object-fit:CSS 属性指定替换元素的内容应该如何适应到其使用的高度和宽度确定的框. object-fit:fill 被替换 ...
- Appium+python自动化(二十三)- 真假美猴王Monkeyrunner与Monkey傻傻的分不清楚(超详解)
简介 看<西游记>第五十七回,说是“六耳猕猴”化作孙悟空的摸样,伤了唐僧,后又和孙悟空大打出手…… 这位假孙悟空,实力不用多说了吧,和真孙悟空一般无二,大战孙悟空,闹到上天入地下海. 在唐 ...
- Git学习笔记 (二)
Git学习笔记(二) 突然发现,学习新知识新技能,都得经常温故使用,这样才能日益精进.最近学习的Git是因为加入了课题组,在学习做一些后台,由于后台开发会牵扯到多人开发,所以学会Git这一代码管理工具 ...
- linux初学者-用户管理篇
linux的用户管理是非常以后工作中重要的一部分,也是linux系统安全的防线. 1.用户理解 那么到底什么是用户呢?用户就是系统使用者的身份. 用户是以怎样的方式储存在计算机中的呢?在系统中用户存储 ...
- LeetCode 解题目录
0001. 两数之和(Java) 0003. 无重复字符的最长子串(Java) 0172. 阶乘后的零 (Java) 0287. 寻找重复数(Java)
- HZOJ 单
两个子任务真的是坑……考试的时候想到了60分的算法,然而只拿到了20分(各种沙雕错,没救了……). 算法1: 对于测试点1,直接n遍dfs即可求出答案,复杂度O(n^2),然而还是有好多同学跑LCA/ ...