JS中队列和双端队列实现及应用详解


Posted in Javascript onSeptember 29, 2020

队列

  • 队列
  • 双端队列数据结构
  • 应用
    • 用击鼓传花游戏模拟循环队列
    • 用双端对列检查一个词是否构成回文
    • 生成 1 到 n 的二进制数

队列和双端队列

队列遵循先进后出(FIFO, 也称为先来先服务) 原则的. 日常有很多这样场景: 排队购票、银行排队等.
由对列的特性,银行排队为例, 队列应该包含如下基本操作:

  • 加入队列(取号) enqueue
  • 从队列中移除(办理业务离开) dequeue
  • 当前排队号码(呼叫下一个人) peek
  • 当前队列长度(当前排队人数) size
  • 判断队列是不是空 isEmpty
class Queue {
  constructor() {
    // 队列长度, 类数组 length
    this.count = 0
    // 队列中所有项
    this.items = {}
    // 记录对列头, 类数组 index
    this.lowestCount = 0
  }

  enqueue(ele) {
    this.items[this.count++] = ele
  }

  dequeue() {
    if (this.isEnpty()) {
      return undefined
    }
    const ele = this.items[this.lowestCount]
    delete this.items[this.lowestCount]
    this.lowestCount++
    return ele
  }

  peek() {
    if (this.isEnpty()) {
      return
    }
    return this.items[this.lowestCount]
  }

  size() {
    /**
    * 当队列为非空时:
    * 1. count 是长度
    * 2. lowestCount 是下标
    * 两者关系应该 lowestCount = count - 1
    */
    return this.count - this.lowestCount
  }

  isEnpty() {
    return this.size() == 0
  }

  clear() {
    this.items = {}
    this.lowestCount = 0
    this.count = 0
  }

  toString() {
    if (this.isEnpty()) {
      return ''
    }
    let objString = `${this.items[this.lowestCount]}`
    for (let i = this.lowestCount + 1; i < this.count; i++) {
    objString = `${objString}, ${this.items[i]}`
    }
    return objString
  }

}

双端队列(deque 或 double-ended queue)

什么是双端队列?

允许从前端(front)和后端(rear)添加元素, 遵循的原则先进先出或后进先出.
双端队列可以理解为就是栈(后进先出)和队列(先进先出)的一种结合体. 既然是结合那么相应的操作也支持队列,栈的操作. 下面我们定义一个Deque

  • addFront
  • removeFront
  • addBack
  • removeBack
  • clear
  • isEmpty
  • peekFront
  • prekBack
  • size
  • toString
  • class Deque {
constructor() {
    this.items = {}
    this.count = 0
    this.lowestCount = 0
  }

  addFront(ele) {
    if (this.isEmpty()) {
      this.items[this.count] = ele
    } else if (this.lowestCount > 0) {
      this.lowestCount -= 1
      this.items[this.lowestCount] = ele
    } else {
      for (let i = this.count; i > 0; i--) {
        this.items[i] = this.items[i - 1]
      }
      this.items[0] = ele
    }
      this.count++
      return ele
    }

  removeFront() {
    if (this.isEmpty()) {
      return
    }
    const delEle = this.items[this.lowestCount]
    delete this.items[this.lowestCount]
    this.lowestCount++
    return delEle
  }

  addBack(ele) {
    this.items[this.count] = ele
    this.count++
  }

  removeBack() {
    if (this.isEmpty()) {
      return
    }

    const delEle = this.items[this.count - 1]
    delete this.items[this.count - 1]
    this.count--
    return delEle
  }

  peekFront() {
    if (this.isEmpty()) {
      return
    }
    return this.items[this.lowestCount]
  }

  peekBack() {
    if (this.isEmpty()) {
      return
    }
    return this.items[this.count - 1]
  }

  size() {
    return this.count - this.lowestCount
  }

  isEmpty() {
    return this.size() === 0
  }

  clear() {
    this.items = {}
    this.count = 0
    this.lowestCount = 0
  }

  toString() {
    if (this.isEmpty()) {
      return ''
    }
    let objString = `${this.items[this.lowestCount]}`
    for (let i = this.lowestCount + 1; i < this.count; i++){
      objString = `${objString}, ${this.items[i]}`
    }
    return objString
  }

}

队列的应用

击鼓传花游戏

击鼓传花游戏: 简单描述就是一群人围成一个圈传递花,喊停的时花在谁手上就将被淘汰(每个人都可能在前端,每个参与者在队列位置会不断变化),最后只剩下一个时就是赢者. 更加详细可以自行查阅.

下面通过代码实现:

function hotPotato(elementsList, num) {
  // 创建一个容器
  const queue = new Queue()
  const elimitatedList = []
  // 把元素(参赛者)加入队列中
  for (let i = 0, len = elementsList.length; i < len; i++) {
    queue.enqueue(elementsList[i])
  }

  /**
  * 击鼓传花
  * 首先队列规则: 先进先出
  * 那么在传花过程中,任何一个元素都可能是前端, 在传花的过程中应该就是前端位置不断变化.
  * 当喊停的时(num 循环完), 也就是花落在谁手(谁在前端)则会被淘汰*(移除队列)
  */

  while (queue.size() > 1) {
    for (let j = 0; j < num; j++) {
      queue.enqueue(queue.dequeue())
    }
    elimitatedList.push(queue.dequeue())
  }
  return {
    winer: queue.dequeue(),
    elimitatedList
  }
}

代码运行如下:

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

console.log(hotPotato(arr, Math.ceil(Math.random() * 10))) // { winer: 5, elimitatedList: [4, 8, 2, 7, 3,10, 9, 1, 6]}
console.log(hotPotato(arr, Math.ceil(Math.random() * 10))) // { winer: 5, elimitatedList: [4, 8, 2, 7, 3,10, 9, 1, 6]}
console.log(hotPotato(arr, Math.ceil(Math.random() * 10))) // { winer: 8, elimitatedList: [10, 1, 3, 6, 2,9, 5, 7, 4]}

判断回文

上一篇栈中也有涉及回文的实现, 下面我们通过双端队列来实现同样的功能.

function palindromeChecker(aString) {
  if (!aString || typeof aString !== 'string' || !aString.trim().length) {
    return false
  }
  const deque = new Deque()
  const lowerString = aString.toLowerCase().split(' ').join('')

  // 加入队列

  for (let i = 0; i < lowerString.length; i++) {
    deque.addBack(lowerString[i])
  }

  let isEqual = true
  let firstChar = ''
  let lastChar = ''

  while (deque.size() > 1 && isEqual) {
    firstChar = deque.removeFront()
    lastChar = deque.removeBack()
    if (firstChar != lastChar) {
      isEqual = false
    }
  }

  return isEqual

}

下面通过代码演示下:

console.log(palindromeChecker('abcba')) // true 当前为回文

JS中队列和双端队列实现及应用详解

生成 1 到 n 的二进制数

function generatePrintBinary(n) {
  var q = new Queue()
  q.enqueue('1')
  while (n-- > 0) {
    var s1 = q.peek()
    q.dequeue()
    console.log(s1)
    var s2 = s1
    q.enqueue(s1 + '0')
    q.enqueue(s2 + '1')
  }
}

generatePrintBinary(5) // => 1 10 11 100 101

到此这篇关于JS中队列和双端队列实现及应用详解的文章就介绍到这了,更多相关JS 双端队列 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
js技巧--转义符&quot;\&quot;的妙用
Jan 09 Javascript
js实现拖拽效果
Feb 12 Javascript
JavaScript实现定时隐藏与显示图片的方法
Aug 06 Javascript
jQuery手动点击实现图片轮播特效
Apr 20 Javascript
JS开发中百度地图+城市联动实现实时触发查询地址功能
Apr 13 Javascript
详解node nvm进行node多版本管理
Oct 21 Javascript
Angular实现较为复杂的表格过滤,删除功能示例
Dec 23 Javascript
微信小程序实现运动步数排行功能(可删除)
Jul 05 Javascript
node+express框架中连接使用mysql(经验总结)
Nov 10 Javascript
javascript实现点击按钮切换轮播图功能
Sep 23 Javascript
微信小程序实现登录注册功能
Dec 29 Javascript
如何使用原生Js实现随机点名详解
Jan 06 Javascript
js实现贪吃蛇游戏(简易版)
Sep 29 #Javascript
js实现星星海特效的示例
Sep 28 #Javascript
vue中重定向redirect:‘/index‘,不显示问题、跳转出错的完美解决
Sep 28 #Javascript
Openlayers绘制聚合标注
Sep 28 #Javascript
Openlayers绘制地图标注
Sep 28 #Javascript
Openlayers实现图形绘制
Sep 28 #Javascript
Openlayers显示瓦片网格信息的方法
Sep 28 #Javascript
You might like
php file_put_contents()功能函数(集成了fopen、fwrite、fclose)
2011/05/24 PHP
php中用于检测一个地理IP地址是否可用的代码
2012/02/19 PHP
基于simple_html_dom的使用小结
2013/07/01 PHP
php数据库的增删改查 php与javascript之间的交互
2017/08/31 PHP
PHP 7.4中使用预加载的方法详解
2019/07/08 PHP
JavaScript 组件之旅(一)分析和设计
2009/10/28 Javascript
JavaScript 类似flash效果的立体图片浏览器
2010/02/08 Javascript
浅谈javascript 归并方法
2015/01/21 Javascript
10个很棒的jQuery代码片段
2015/09/24 Javascript
js弹出对话框方式小结
2015/11/17 Javascript
微信小程序学习(4)-系统配置app.json详解
2017/01/12 Javascript
原生JS实现图片翻书效果
2017/02/16 Javascript
jQuery remove()过滤被删除的元素(推荐)
2017/07/18 jQuery
Webpack中publicPath路径问题详解
2018/05/03 Javascript
小程序点赞收藏功能的实现代码示例
2018/09/07 Javascript
vue  自定义组件实现通讯录功能
2018/09/30 Javascript
vue中添加与删除关键字搜索功能
2019/10/12 Javascript
[01:57]2018DOTA2亚洲邀请赛赛前采访-iG
2018/04/03 DOTA
Matplotlib 生成不同大小的subplots实例
2018/05/25 Python
使用keras框架cnn+ctc_loss识别不定长字符图片操作
2020/06/29 Python
keras自动编码器实现系列之卷积自动编码器操作
2020/07/03 Python
Selenium关闭INFO:CONSOLE提示的解决
2020/12/07 Python
termux中matplotlib无法显示中文问题的解决方法
2021/01/11 Python
彻底弄明白CSS3的Media Queries(跨平台设计)
2010/07/27 HTML / CSS
h5调用摄像头的实现方法
2016/06/01 HTML / CSS
高清屏下canvas重置尺寸引发的问题的解决
2019/10/14 HTML / CSS
建筑设计所实习生自我鉴定
2013/09/25 职场文书
生产车间主管岗位职责
2013/12/28 职场文书
公司人力资源的自我评价
2014/01/02 职场文书
残疾人创业典型事迹
2014/02/01 职场文书
无刑事犯罪记录证明
2014/09/18 职场文书
社区党风廉政建设调研报告
2015/01/01 职场文书
后进生评语大全
2015/01/04 职场文书
社区志愿服务活动感想
2015/08/07 职场文书
JavaWeb 入门篇:创建Web项目,Idea配置tomcat
2021/07/16 Java/Android
Redis模仿手机验证码发送的实现示例
2021/11/02 Redis