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 相关文章推荐
Javascript 构造函数 实例分析
Nov 26 Javascript
javascript开发技术大全-第1章javascript概述
Jul 03 Javascript
node.js中的fs.renameSync方法使用说明
Dec 16 Javascript
JavaScript实现列出数组中最长的连续数
Dec 29 Javascript
js仿QQ中对联系人向左滑动、滑出删除按钮的操作
Apr 07 Javascript
举例讲解jQuery中可见性过滤选择器的使用
Apr 18 Javascript
使用Bootstrap美化按钮实例代码(demo)
Feb 03 Javascript
vue在手机中通过本机IP地址访问webApp的方法
Aug 15 Javascript
详解swiper在vue中的应用(以3.0为例)
Sep 20 Javascript
JS中的变量作用域(console版)
Jul 18 Javascript
JavaScript实现淘宝商品图切换效果
Apr 29 Javascript
二维码条形码生成的JavaScript脚本库
Jul 07 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 遍历显示文件夹下所有目录、所有文件的函数,没有分页的代码
2008/11/14 PHP
浅析PHP程序设计中的MVC编程思想
2014/07/28 PHP
PHP将Excel导入数据库及数据库数据导出至Excel的方法
2015/06/24 PHP
yii使用bootstrap分页样式的实例
2017/01/17 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
2019/11/26 PHP
枚举JavaScript对象的函数
2006/12/22 Javascript
js新闻滚动 js如何实现新闻滚动效果
2013/01/07 Javascript
浅析jQuery对select操作小结(遍历option,操作option)
2013/07/04 Javascript
纯JS实现动态时间显示代码
2014/02/08 Javascript
js取整数、取余数的方法
2014/05/11 Javascript
jquery.uploadify插件在chrome浏览器频繁崩溃解决方法
2015/03/01 Javascript
Javascript中浏览器窗口的基本操作总结
2016/08/18 Javascript
jQuery实现滚动效果
2017/11/17 jQuery
vue-awesome-swiper滑块插件使用方法详解
2017/11/27 Javascript
JavaScript递归函数定义与用法实例分析
2019/01/24 Javascript
VuePress 快速踩坑小结
2019/02/14 Javascript
webpack4手动搭建Vue开发环境实现todoList项目的方法
2019/05/16 Javascript
JS回调函数 callback的理解与使用案例分析
2019/09/09 Javascript
JavaScript实现随机点名小程序
2020/10/29 Javascript
Python实现生成简单的Makefile文件代码示例
2015/03/10 Python
Python中列表的一些基本操作知识汇总
2015/05/20 Python
解决在Python编辑器pycharm中程序run正常debug错误的问题
2019/01/17 Python
python getopt模块使用实例解析
2019/12/18 Python
python orm 框架中sqlalchemy用法实例详解
2020/02/02 Python
TensorFlow的reshape操作 tf.reshape的实现
2020/04/19 Python
python中id函数运行方式
2020/07/03 Python
HTML5的postMessage的使用手册
2018/12/19 HTML / CSS
Gibson London官网:以地道的英国男装而著称
2019/12/06 全球购物
银行求职推荐信范文
2013/11/30 职场文书
远程研修随笔感言
2014/02/10 职场文书
2015年防灾减灾工作总结
2015/07/24 职场文书
《认识钟表》教学反思
2016/02/16 职场文书
倡议书怎么写?
2019/04/11 职场文书
css实现文章分割线样式的多种方法总结
2021/04/21 HTML / CSS
pandas DataFrame.shift()函数的具体使用
2021/05/24 Python
关于springboot 配置date字段返回时间戳的问题
2021/07/25 Java/Android