我们知道在 JS 中,删除数组元素有两个方法:pop
与 shift
,分别可以删除末尾与开头的元素。
然而同样是删除元素,它们的执行时间确实不同的。
当数组项目较多时,shift
的执行时间明显长于 pop
。
const test = (arrLength) => {
let arr1 = []
console.time(`${arrLength}-arr1`)
for (let i = 0; i < arrLength; i++) {
arr1.push(i)
}
for (let i = 0; i < arrLength; i++) {
arr1.pop()
}
console.timeEnd(`${arrLength}-arr1`)
let arr2 = []
console.time(`${arrLength}-arr2`)
for (let i = 0; i < arrLength; i++) {
arr2.push(i)
}
for (let i = 0; i < arrLength; i++) {
arr2.shift()
}
console.timeEnd(`${arrLength}-arr2`)
}
test(10 ** 5)
test(10 ** 6)
结果如下:
这是因为 pop
删除元素后不需要改变其他元素的索引,时间复杂度为 O(1);而调用 shift
方法删除开头元素后,需要维护数组的索引,相当于对数组中的所有元素都进行了一次赋值操作,其时间复杂度为 O(n)
栈与队列
栈与队列是我们常用的两种数据结构。
栈的元素先进后出,比如函数栈,函数递归调用时,后调用的函数先执行完。
队列的元素先进先出,比如任务队列,任务按照派发的顺序依次执行。
在 JS 中,栈可以看成只调用 push
与 pop
方法的数组,队列可以看成是只调用 shift
与 push
方法的数组。
然而在之前的例子中也看到了,当处理大量数据时,把数组直接当成队列使用性能非常差。
所以,我们要设法实现队列这一数据结构。
如何实现?
开始之前我们要明确实现的目标,我们实现的队列要提供以下几个功能:
- 存储数据:队列要能够按序存储数据
push
:添加元素的唯一方法,将元素添加进队列尾部的方法,并返回队列长度shift
:删除元素的唯一方法,将队首元素删除的方法,并返回删除的元素length
:可以通过 length 属性访问队列的长度- 访问元素:一般队列会允许访问队头与队尾的元素