JavaScript版:数据结构之“队列”

2,128 阅读3分钟

1. 队列

  • 先进先出的数据结构
  • js中没有队列,但是可以使用array来实现队列
    • 入队 push()
    • 出队 shift()

image.png

const queue = [];
//入队
queue.push(1); // [1]
queue.push(2); // [1, 2]

// 出队
const item1 = queue.shift(); // 1
const item2 = queue.shift(); // 2

2. 什么场景用队列

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

2.1 场景一:食堂排队打饭

  • 食堂只留一个窗口,学生排队打饭似春运
  • 先进先出,保证有序

2.3 场景二:JS异步中的任务队列

image.png

  • JS 是单线程,无法同时处理异步中的并发任务
  • 使用任务队列先后处理异步任务

2.3 场景三:计算最近请求次数

image.png

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

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

image.png

3.1 解题思路

  • 越早发的的请求越早不在最近3000ms内的请求里;
  • 满足先进先出,考虑用队列;

3.2 解题步骤

  • 有新请求就入队,300ms前发出的请求出队
  • 队列的长度就是最近的请求次数
var RecentCounter = function () {
    this.q = [];
};

/** 
 * @param {number} t
 * @return {number}
 */
RecentCounter.prototype.ping = function (t) {
    this.q.push(t)
    while (this.q[0] < t - 3000) {
        this.q.shift()
    }
    return this.q.length;
};

/**
 * Your RecentCounter object will be instantiated and called as such:
 * var obj = new RecentCounter()
 * var param_1 = obj.ping(t)
 */
  • 本题结果:时间复杂度 O(n)、空间复杂度 O(n)

4. 前端与队列:JS异步中的任务队列

维基百科的定义是:“事件循环是一个程序结构,用于等待和发送消息和事件(a programming construct that waits for and dispatches events or messages in a program)”。

4.1 异步面试题

setTimeout(()=>console.log(1), 0);
console.log(2);
  • 输出结果

image.png

  • 原理
  • 先有一个主事件放到任务队列中,然后JS引擎会拿到 主事件 去执行
  • 执行setTimeout 发现是一异步任务,就交给web API去执行,web API 在0ms 就执行完了,
  • 接着把执行完的回掉函数console.log(1)放人任务中,
  • 但是发现还有一个任务队列console.log(2)没有执行完
  • 所以先打印2 再打印1

4.2 事件循环与任务队列

image.png

4.3 主线程和任务队列

JavaScript 运行时,除了一个正在运行的主线程,引擎还提供一个任务队列(task queue),里面是各种需要当前程序处理的异步任务。(实际上,根据异步任务的类型,存在多个任务队列。为了方便理解,这里假设只存在一个队列。)

首先,主线程会去执行所有的同步任务。等到同步任务全部执行完,就会去看任务队列里面的异步任务。

如果满足条件,那么异步任务就重新进入主线程开始执行,这时它就变成同步任务了。等到执行完,下一个异步任务再进入主线程开始执行。一旦任务队列清空,程序就结束执行。

4.3 异步任务的写法通常是回调函数

一旦异步任务重新进入主线程,就会执行对应的回调函数。如果一个异步任务没有回调函数,就不会进入任务队列,也就是说,不会重新进入主线程,因为没有用回调函数指定下一步的操作。

4.5 事件循环

JavaScript 引擎怎么知道异步任务有没有结果,能不能进入主线程呢?答案就是引擎在不停地检查,一遍又一遍,只要同步任务执行完了,引擎就会去检查那些挂起来的异步任务,是不是可以进入主线程了。这种循环检查的机制,就叫做事件循环(Event Loop)。

5 队列总结

  • 队列是一个先进先出的数据结构

  • js中没有队列,但是可以使用array来实现队列

    • 入队 push()
    • 出队 shift()
    • 获取队头元素 queue[0]
  • 树 和 图的数据结构时也会使用到队列进行广度和深度优先遍历