队列

基本概念

队列是一种先进先出(FIFO,First In First Out)的数据结构。只用 pushshift 完成增删的“数组”。

很好理解,就跟银行排队一样,先排的人先办业务。

JS实现队列

Class Queue {
    constructor() {
        this.queue = []    
    }
    enqueue(item) {
        this.queue.push(item)    
    }
    dequeue() {
        return this.queue.shift()    
    }
    head() {
        return  this.queue[0] 
    }
    isEmpty(){
        return this.size() === 0    
    }
    size(){
        return this.queue.length    
    }
}

优先队列

优先队列是默认队列的变种,它的元素的添加和移除是基于优先级的。一个现实的例子就是医院的(急诊科)候诊室。医生会优先处理病情比较严重的患者。

实现一个优先队列,有两种选择:

  • 设置优先级,然后在正确的位置添加元素;
  • 用默认入列操作添加元素,按照优先级移除它们。
class QueueItem {
  constructor(item, priority) {
    this.item = item
    this.priority = priority
  }
}

class PriorityQueue {
  constructor() {
    this.queue = []
  }

  enqueue(item, priority) {
    const qItem = new QueueItem(item, priority)
    if (this.isEmpty()) {
      this.queue.push(qItem)
    } else {
      let added = false
      for (let i = 0; i < this.queue.length; i++) {
        if (priority < this.queue[i].priority) {
          this.queue.splice(i, 0, qItem) //在index:i的位置插入
          added = true
          break
        }
      }
      if (!added) {
        this.queue.push(qItem)
      }
    }
  }

  dequeue() {
    return this.queue.shift()
  }

  head() {
    return this.queue[0]
  }

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

  size() {
    return this.queue.length
  }

  print() {
    return this.queue.map(q => q.item)
  }
}

var queue = new PriorityQueue()
console.log(queue.isEmpty()) // 输出 true
queue.enqueue('a', 4)           // 添加元素 a
queue.enqueue('b', 2)           // 添加元素 b
queue.enqueue('c', 1)           // 添加元素 c
queue.enqueue('d', 1)           // 添加元素 d
console.log(queue.print())        // 输出 ['c','d','b','a']

循环队列

循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。

但是使用循环队列,我们能使用这些空间去存储新的值。

因为单链队列在出队操作的时候需要 O(n) 的时间复杂度,所以引入了循环队列。循环队列的出队操作平均是 O(1) 的时间复杂度。

典型的应用就是击鼓传花与约瑟夫环问题。

class Queue {
  constructor() {
    this.queue = []
  }

  enqueue(item) {
    this.queue.push(item)
  }

  dequeue() {
    return this.queue.shift()
  }

  head() {
    return this.queue[0]
  }

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

  size() {
    return this.queue.length
  }
}

function flowerDrumTransfer(nodeList, counter) {
  const queue = new Queue()
  for (let i = 0; i < nodeList.length; i++) {
    queue.enqueue(nodeList[i])
  }

  let target = ''
  while (queue.size() > 1) {
    for (let j = 0; j < counter; j++) {
      queue.enqueue(queue.dequeue())
    }
    target = queue.dequeue() //该轮中被淘汰出局的
  }
  return queue.dequeue()
}

const arr = ['a', 'b', 'c', 'd', 'e']
const winner = flowerDrumTransfer(arr, 7)
console.log(winner)