数据结构与算法之队列(二)

1,700 阅读2分钟

队列实现

  • 先进先出的数据结构,可以想象排队,先到窗口的先办理业务
  • 往后添加新元素的一端称为队尾,另一端称为队首
  • js没有队列,我们可以使用 Array 模拟队列所有功能
const queue = [];

// 入队
queue.push(1);
queue.push(2);

// 出队
const first = queue.shift();
const end = queue.shift();

手写模拟队列(基于对象):

class Queue {
  constructor() {
    this.queue = {};
    this.count = 0;
    // 用于记录队首的键
    this.head = 0;
  }
  // 入队方法
  enQueue(item) {
    this.queue[this.count++] = item;
  }
  // 出队方法
  deQueue() {
    if (this.isEmpty()) {
      return;
    }
    const headData = this.queue[this.head];
    delete this.queue[this.head];
    this.head++;
    this.count--;
    return headData;
  }
  isEmpty() {
    return this.count === 0;
  }
  clear() {
    this.queue = {};
    this.count = 0;
    this.head = 0;
  }
}

const q = new Queue();

使用两个栈模拟队列:

// 时间复杂度:add:O(1)  delete:O(n)
// 空间复杂度,整体是O(n)
class MyQueue {
  stack1 = [];
  stack2 = [];

  add(n) {
    this.stack1.push(n);
  }
  delete() {
    const stack1 = this.stack1;
    const stack2 = this.stack2;

    // 将 stack1 所有元素 pop 出来,push 到 stack2
    while (stack1.length) {
      const n1 = stack1.pop();
      if (n1 != null) {
        stack2.push(n1);
      }
    }

    // 将 stack2 执行一次 pop
    const resultDelete = stack2.pop();

    // 再将 stack2 所有元素 pop 出来,push 进 stack1
    while (stack2.length) {
      const n1 = stack2.pop();
      if (n1 != null) {
        stack1.push(n1);
      }
    }
    return resultDelete || null;
  }
  get length() {
    return this.stack1.length;
  }
}

const q = new MyQueue();
q.add("a");
q.add("b");
q.add("c");
console.log(q.delete()); // a
console.log(q.length); // 2

什么场景用队列

  • 需要先进先出的场景
  • 比如:食堂排队打饭、JS异步中的任务队列、计算最近请求次数

1、食堂排队打饭

  • 食堂只留一个窗口,学生排队打饭似春运

  • 先进先出,保证有序

2、JS异步的任务队列

  • JS是单线程,无法同时处理异步中的并发任务

  • 使用任务队列先后处理异步任务

3、LeetCode: 933.最近的请求次数

  • 有新请求就入队,3000ms前发出的请求出队
  • 队列的长度就是最近请求次数

解题思路

  • 越早发出的请求越早不在最近3000ms内的请求里
  • 满足先进先出,考虑用队列
var RecentCounter = function() {
    this.queue = []
};

// 时间复杂度 O(n) n为剔出老请求的长度
// 空间复杂度 O(n) n为最近请求的次数
RecentCounter.prototype.ping = function(t) {
    this.queue.push(t)
    while(this.queue[0] < t - 3000) {
        this.queue.shift();
    }
    return this.queue.length
};