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 相关文章推荐
云网广告中的代码,提示出错,大家找找
Nov 21 Javascript
javascript编程起步(第五课)
Feb 27 Javascript
JQuery中dataGrid设置行的高度示例代码
Jan 03 Javascript
Node.js中HTTP模块与事件模块详解
Nov 14 Javascript
微信小程序--组件(swiper)详细介绍
Jun 13 Javascript
JS仿QQ好友列表展开、收缩功能(第一篇)
Jul 07 Javascript
jQuery.Ajax()的data参数类型详解
Jul 23 jQuery
微信小程序简单实现form表单获取输入数据功能示例
Nov 30 Javascript
利用SpringMVC过滤器解决vue跨域请求的问题
Feb 10 Javascript
Vue在 Nuxt.js 中重定向 404 页面的方法
Apr 23 Javascript
Typescript3.9 常用新特性一览(推荐)
May 14 Javascript
微信小程序 button样式设置为图片的方法
Jun 19 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
WML,Apache,和 PHP 的介绍
2006/10/09 PHP
php.ini 配置文件的深入解析
2013/06/17 PHP
php中将一段数据存到一个txt文件中并显示其内容
2014/08/15 PHP
php遍历解析xml字符串的方法
2016/05/05 PHP
PHP进程通信基础之信号量与共享内存通信
2017/02/19 PHP
PHP实现数组转JSon和JSon转数组的方法示例
2018/06/14 PHP
javascript 装载iframe子页面,自适应高度
2009/03/20 Javascript
jQuery 图像裁剪插件Jcrop的简单使用
2009/05/22 Javascript
JavaScript几种形式的树结构菜单
2010/05/10 Javascript
jquery text(),val(),html()方法区别总结
2013/11/04 Javascript
js字符串截取函数substr substring slice使用对比
2013/11/27 Javascript
JS+CSS实现实用的单击输入框弹出选择框的方法
2015/02/28 Javascript
jquery插件jquery.nicescroll实现图片无滚动条左右拖拽的方法
2015/08/10 Javascript
原生JS查找元素的方法(推荐)
2016/11/22 Javascript
js addDqmForPP给标签内属性值加上双引号的函数
2016/12/24 Javascript
vue.js响应式原理解析与实现
2020/06/22 Javascript
深入理解JavaScript 箭头函数
2019/05/30 Javascript
解决layer弹出层的内容页点击按钮跳转到新的页面问题
2019/09/14 Javascript
Vue可自定义tab组件用法实例
2019/10/24 Javascript
微信小程序如何通过用户授权获取手机号(getPhoneNumber)
2020/01/21 Javascript
vue渲染方式render和template的区别
2020/06/05 Javascript
对Python中内置异常层次结构详解
2018/10/18 Python
利用python将图片版PDF转文字版PDF
2019/05/03 Python
python 的 openpyxl模块 读取 Excel文件的方法
2019/09/09 Python
python实现操作文件(文件夹)
2019/10/31 Python
Python IDE环境之 新版Pycharm安装详细教程
2020/03/05 Python
python设置中文界面实例方法
2020/10/27 Python
python3访问字典里的值实例方法
2020/11/18 Python
花园仓库建筑:Garden Buildings Direct
2018/02/16 全球购物
Senreve官网:美国旧金山的奢侈手袋品牌
2019/03/21 全球购物
英国100%防污和防水的靴子:Muck Boot Company
2020/09/08 全球购物
哥伦比亚加拿大官网:Columbia Sportswear Canada
2020/09/07 全球购物
地心历险记观后感
2015/06/15 职场文书
matlab xlabel位置的设置方式
2021/05/21 Python
Python利用Turtle绘制哆啦A梦和小猪佩奇
2022/04/04 Python
Win11安全功能升级:内置防网络钓鱼功能
2022/04/08 数码科技