JS 数据结构 —— 队列

1,966 阅读3分钟

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动。
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

昨个儿写了篇介绍栈结构的文章,本篇继续介绍另一种线性表 —— 队列结构的内容,有不足之处或是任何意见建议,欢迎各位大佬不吝斧正~

定义

队列(Queue,发音为 [kjuː] ),是一种基于先进先出(First In First Out,简称 FIFO)的数据结构,是一种受限的线性表,只能在一端(前端,front)进行插入,另一端(后端,rear)进行删除操作。 image.png

封装队列结构

js 中没有现成的队列结构,但我们可以基于数组自己封装一个构造函数 Queue,并实现队列的入队、出队、查看队列第一个元素、检查队列是否为空和将队列内容转成字符串这 5 个队列常用操作的方法:

function Queue() {
  this.items = []
  // 入队
  Queue.prototype.push = function (item) {
    this.items.push(item)
  }
  // 出队
  Queue.prototype.shift = function () {
    return this.items.shift()
  }
  // 查看队列第一个元素
  Queue.prototype.first = function () {
    return this.items[0]
  }
  // 检查队列是否为空
  Queue.prototype.isEmpty = function () {
    return this.items.length === 0
  }
  // 将队列内容转成字符串
  Queue.prototype.toString = function () {
    return this.items.toString()
  }
}

// new 一个队列实例
const queue = new Queue()

案例

这不刚好今天 lol 的 S11 世界赛要开始打入围赛了,这里写一个小游戏预测一波冠军。规则如下:几大夺冠热门战队围一圈依次报数,报到数字 7 的人直接淘汰,直至剩下最后一支战队,成为预言冠军,游戏结束。

function drinkingGame(crowd, number) {
  // new 一个队列实例
  const queue = new Queue()
  // 将 crowd 里的每一项都放入队列中
  crowd.forEach((item) => queue.push(item))
  while (crowd.length > 1) {
    // 只要是小于 number 的那一项,就从队列取出,再放回队列中
    for (let index = 0; index < number - 1; index++) {
      crowd.push(crowd.shift())
    }
    // 将 for 循环前的第 number 项删除(也就是现在的队列的首项)
    crowd.shift()
  }
  console.log(crowd.toString())
}

drinkingGame(['Rng', 'T1', 'EDG', 'DWG', 'FPX'], 7)

很遗憾,xdm,我这次预测的结果冠军是 DWG,希望是反向预测~

优先级队列

普通队列是新插入的元素永远会被放在最后一个,而优先级队列则是将每个元素赋予优先级,在插入元素时考虑该元素的优先级与队列中其它元素的优先级的重要关系,将优先级高的元素放在优先级低的元素之前。比如提交测试 bug,那么优先级为 1 的就应该最先被处理,而优先级为 5 的则可以延迟处理。

function PriorityQueue() {
  // 先创建一个 Item 构造函数,用于创建加入优先级队列的元素
  function Item(item, p) {
    this.element = item
    this.priority = p
  }
  // 继承队列 Queue 的属性
  Queue.call(this)
  // 重写属于优先级队列 push 方法
  PriorityQueue.prototype.push = function (newItem, p) {
    const item = new Item(newItem, p)
    // 如果队列为空,则直接将新元素加入
    if (this.isEmpty()) {
      this.items.push(item)
    } else {
      let isPush = false // 记录是否插入成功
      // 如果遇到优先级比自己的低(priority 更大)的则插入到该元素之前
      for (let index = 0; index < this.items.length; index++) {
        if (item.priority < this.items[index].priority) {
          this.items.splice(index, 0, item)
          isPush = true
          break
        }
      }
      // 如果优先级都比自己高
      if (!isPush) {
        this.items.push(item)
      }
    }
  }
}
// 继承队列 Queue 的方法
PriorityQueue.prototype = Object.create(Queue.prototype)

可以测试一下:

const priorityQueue = new PriorityQueue()
priorityQueue.push('五级 bug', 5)
priorityQueue.push('一级 bug', 1)
priorityQueue.push('三级 bug', 3)
priorityQueue.push('二级 bug', 2)
console.log(priorityQueue)

得到结果如下:

image.png

感谢.gif 点赞.png