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 相关文章推荐
HTML中Select不用Disabled实现ReadOnly的效果
Apr 07 Javascript
基于jquery插件制作左右按钮与标题文字图片切换效果
Nov 07 Javascript
javasciprt下jquery函数$.post执行无响应的解决方法
Mar 13 Javascript
jQuery构造函数init参数分析续
May 13 Javascript
AJAX实现瀑布流触发分页与分页触发瀑布流的方法
May 23 Javascript
js注入 黑客之路必备!
Sep 14 Javascript
实现点击下箭头变上箭头来回切换的两种方法【推荐】
Dec 14 Javascript
Angular js 实现添加用户、修改密码、敏感字、下拉菜单的综合操作方法
Oct 24 Javascript
Node.js 利用cheerio制作简单的网页爬虫示例
Mar 01 Javascript
vue click.stop阻止点击事件继续传播的方法
Sep 04 Javascript
javascript设计模式 ? 代理模式原理与用法实例分析
Apr 16 Javascript
解决VUE自定义拖拽指令时 onmouseup 与 click事件冲突问题
Jul 24 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中使用Imagick操作PSD文件实例
2015/01/26 PHP
Yii2简单实现给表单添加验证码的方法
2016/07/18 PHP
js下写一个事件队列操作函数
2010/07/19 Javascript
基于OO的动画附加插件,可以实现弹跳、渐隐等动画效果 分享
2013/06/24 Javascript
纯js分页代码(简洁实用)
2013/11/05 Javascript
JS小功能(offsetLeft实现图片滚动效果)实例代码
2013/11/28 Javascript
ie8本地图片上传预览示例代码
2014/01/12 Javascript
node.js中实现同步操作的3种实现方法
2014/12/05 Javascript
JavaScript中几种排序算法的简单实现
2015/07/29 Javascript
JavaScript每天必学之数组和对象部分
2016/09/17 Javascript
JavaScript ES6中CLASS的使用详解
2016/11/22 Javascript
原生javascript实现图片放大镜效果
2017/01/18 Javascript
微信小程序自定义导航隐藏和显示功能
2017/06/13 Javascript
详解webpack3如何正确引用并使用jQuery库
2017/08/26 jQuery
纯js封装的ajax功能函数与用法示例
2018/05/14 Javascript
基于element-ui对话框el-dialog初始化的校验问题解决
2020/09/11 Javascript
python中关于时间和日期函数的常用计算总结(time和datatime)
2013/03/08 Python
Python实现二分法算法实例
2015/02/02 Python
Python使用回溯法子集树模板解决迷宫问题示例
2017/09/01 Python
对Python中list的倒序索引和切片实例讲解
2018/11/15 Python
python读取有密码的zip压缩文件实例
2019/02/08 Python
Jupyter notebook运行Spark+Scala教程
2020/04/10 Python
python名片管理系统开发
2020/06/18 Python
pycharm导入源码的具体步骤
2020/08/04 Python
HTML5的自定义属性data-*详细介绍和JS操作实例
2014/04/10 HTML / CSS
世界上最值得信赖的多日游在线市场:TourRadar
2018/07/20 全球购物
介绍Java的内部类
2012/10/27 面试题
学生处主任岗位职责
2013/12/01 职场文书
现金会计岗位职责
2013/12/05 职场文书
获奖的大学生创业计划书
2014/01/05 职场文书
甜品店创业计划书
2014/09/21 职场文书
升职自我推荐信范文
2015/03/25 职场文书
外出学习心得体会范文
2016/01/18 职场文书
Redis可视化客户端小结
2021/06/10 Redis
微信小程序APP的事件绑定以及传递参数时的冒泡和捕获
2022/04/19 Javascript
pytorch实现加载保存查看checkpoint文件
2022/07/15 Python