队列(Queue)是一种常见的数据结构,它类似于排队的形式,遵循 先进先出(FIFO) 的原则。在队列中,元素在尾部添加,而在头部移除。这就类似于排队时,先来的人先服务,后来的人排在后面等待服务。
队列,和栈一样,也是一种对数据的"存"和"取"有严格要求的线性存储结构。
与栈结构不同的是,队列的两端都"开口",要求数据 只能从一端进,从另一端出 ,如图 1 所示:
通常,称进数据的一端为 "队尾",出数据的一端为 "队头",数据元素进队列的过程称为 "入队",出队列的过程称为 "出队"。
不仅如此,队列中数据的进出要遵循 “先进先出” 的原则,即最先进队列的数据元素,同样要最先出队列。
拿图 1 中的队列来说,从数据在队列中的存储状态可以分析出,元素 1 最先进队,其次是元素 2,最后是元素 3。
此时如果将元素 3 出队,根据队列 “先进先出” 的特点,元素 1 要先出队列,元素 2 再出队列,最后才轮到元素 3 出队列。
栈和队列不要混淆,栈结构是一端封口,特点是"先进后出";而队列的两端全是开口,特点是"先进先出"。
因此,数据从表的一端进,从另一端出,且遵循 “先进先出” 原则的线性存储结构就是队列。
队列通常包括以下几种基本操作:
队列常常用于实现广度优先搜索(BFS)、线程池、缓存等应用场景,是计算机科学中非常重要的数据结构之一。
更多详细内容,请微信搜索“前端爱好者
“, 戳我 查看 。
JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。
那么,为什么JavaScript 不能有多个线程呢 ?这样能提高效率啊。
JavaScript 的单线程,与它的用途有关。
作为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操作 DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。
比如,假定JavaScript 同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
所以,为了避免复杂性,从一诞生,JavaScript 就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
一种非阻塞的事件循环机制就产生了:
在JavaScript中,消息队列是事件驱动架构的核心部分,用于管理异步任务的执行顺序。
由于JavaScript在浏览器环境中被设计为单线程(即同一时间只能执行一个任务),为了处理异步操作(如网络请求、定时器、DOM事件等),它采用了一种非阻塞的事件循环机制。
初始阶段:JS引擎开始执行全局脚本(这也是一个宏任务)。
同步执行:从上到下逐行执行代码,遇到异步操作(如fetch
请求或setTimeout
调用)则不会阻塞执行流,而是将回调函数放入相应的消息队列。
检查微任务队列:当前宏任务执行完毕后,立即查看微任务队列是否有待执行的任务。如果有,则按先进先出(FIFO)原则执行所有微任务。
渲染阶段:在执行完所有的微任务之后,浏览器会进行一次渲染更新(如果有必要的话)。
检查宏任务队列:然后轮询宏任务队列,取出第一个宏任务来执行。
重复循环:以上步骤不断循环,形成了所谓的“事件循环”。
因此,在JavaScript中,消息队列不是单一的一个队列,而是至少包含两个层次的任务队列(宏任务队列和微任务队列)。
这种结构确保了即使在单线程环境下,也能实现异步编程和高效的并发处理能力。
这种机制就叫做事件循环机制,取一个消息并执行的过程叫做一次循环。
写一个 RecentCounter 类来计算特定时间范围内最近的请求。
请你实现 RecentCounter 类:
示例 1:
输入:
["RecentCounter", "ping", "ping", "ping", "ping"]
[[], [1], [100], [3001], [3002]]
输出:
[null, 1, 2, 3, 3]
解释:
RecentCounter recentCounter = new RecentCounter();
recentCounter.ping(1); // requests = [1],范围是 [-2999,1],返回 1
recentCounter.ping(100); // requests = [1, 100],范围是 [-2900,100],返回 2
recentCounter.ping(3001); // requests = [1, 100, 3001],范围是 [1,3001],返回 3
recentCounter.ping(3002); // requests = [1, 100, 3001, 3002],范围是 [2,3002],返回 3
提示:
1 <= t <= 109
保证每次对 ping 调用所使用的 t 值都 严格递增
至多调用 ping 方法 10^4 次
实现代码
var RecentCounter = function () {
// 新建一个队列,用于存储数据
this.stack = []
}
/**
* @param {number} t
* @return {number}
*/
RecentCounter.prototype.ping = function (t) {
// 把数据存储在队列中
this.stack.push(t)
while (this.stack[0] < t - 3000) {
// 如果满足条件,则出队
this.stack.shift(t)
}
return this.stack.length
};
/**
* Your RecentCounter object will be instantiated and called as such:
* var obj = new RecentCounter()
* var param_1 = obj.ping(t)
*/
参考文档