作为一个优秀的程序猿需要具有知识的广度。首先是要了解你选择的编程语言。如果你正在阅读这篇文章,最有可能使用 JavaScript。
然而在熟悉了编程语言之后,你还必须了解如何根据任务轻松且有效地操纵数据。这就是数据结构的用武之地。
在本文中,我将描述队列数据这个结构:它都有哪些操作以及在 JavaScript 中怎样实现。
1. 队列数据结构
如果你喜欢四处旅行,肯定在火车站经历过检票这道手续。如果有很多人要坐火车,那么很自然地会形成一个队列。刚进入车站的人加入队列。另一边刚刚通过检票的人从队列中走出。这就是队列的一个例子,与队列数据结构的操作方式相同。
队列是一种遵循先入先出(FIFO)规则的数据结构。第一个进入队列中的项目(输入)是第一个出队(输出)的。
队列有2个指针:队首和队尾。最先进入队列进行排队的项目位于队首,而最后进入队列的项目位于队尾。
回顾车站的例子,第一个检票的是在队列的队首。刚进入队列的人在队尾。
从更高的层面来看,队列是一种允许你按照先后顺序处理项目的数据结构。
2. 队列的操作
队列支持 2 个主要操作:入队(enqueue)和出队(dequeue),另外还有 peek 和 length 操作。
2.1 入队操作
入队操作在队列的尾部插入项目,使其成为队列的队尾。
上图中的入队操作在队尾插入了 8
,之后 8
成为队列的队尾。
queue.enqueue(8);
2.2 出队操作
出队操作取出队列中第一个项目,此时队列中的下一个项目成为队首。
在上图中,出队操作返回项目7
并从队列中删除。 出队之后之后,项目 2
成为新的队首。
queue.dequeue(); // => 7
2.3 Peek 操作
Peek 操作读取队首的项目,但是不改变队列。
上图中 7
是队首。 peek 操作只需返回队首 7
但是不修改队列。
queue.peek(); // => 7
2.4 length
length 操作返回队列中包含项目的数量。
上图中的队列有 4 项:4
、6
、2
和。7
。结果队列长度为 4
。
queue.length; // => 4
2.5 队列操作的时间复杂度
关于队列所有操作的重点:enqueue,dequeue,peek 和 length 必须以常数时间复杂度 O(1)
执行。
常数时间复杂度 O(1)
意味着无论队列大小如何(不管是有 10 个还是 100 万个项目),这些操作都必须在相对一致的时间内执行。
3. 用 JavaScript 实现队列
来看一下怎样在保证所有操作必须以常数时间复杂度O(1)
要求实现队列这种数据结构。
class Queue {
constructor() {
this.items = {};
this.headIndex = 0;
this.tailIndex = 0;
}
enqueue(item) {
this.items[this.tailIndex] = item;
this.tailIndex++;
}
dequeue() {
const item = this.items[this.headIndex];
delete this.items[this.headIndex];
this.headIndex++;
return item;
}
peek() {
return this.items[this.headIndex];
}
get length() {
return this.tailIndex - this.headIndex;
}
}
const queue = new Queue();
queue.enqueue(7);
queue.enqueue(2);
queue.enqueue(6);
queue.enqueue(4);
queue.dequeue(); // => 7
queue.peek(); // => 2
queue.length; // => 3
const queue = new Queue()
是创建队列的实例。
queue.enqueue(7)
方法将 7
存入队列中。
queue.dequeue()
从队列中取出一个头部项目,而 queue.peek()
只读队首项。
最后的 Queue.Length
显示队列中还有多少个项目。
关于实现:在 Queue
类中,普通对象 this.Items
将队列的项目通过数值索引保持。 队首项的索引由 Where.HeadInex
跟踪,队尾项由 this.tailIndex
跟踪。
队列方法的复杂度
在 Queue
的 queue()
、 dequeue()
、 peek()
和 length()
方法中存在:
- 属性访问器(如:
this.items[this.headIndex]
), - 执行算数操作(如:
this.headidex++
)
这些方法的时间复杂度是恒定的时间 O(1)
。
4. 总结
队列是一种遵循先入先出(FIFO)规则的的数据结构。
队列有 2 个主要操作:入队和出队。 另外,队列可以有辅助操作,例如 peek 和 length。
所有队列操作都必须以常数时间 O(1)
执行。
挑战一下:改进 dequeue()
和 peek()
方法,当在空队列上执行时会抛出错误。
本文首发微信公众号:前端先锋
欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章
欢迎继续阅读本专栏其它高赞文章:
- 深入理解Shadow DOM v1
- 一步步教你用 WebVR 实现虚拟现实游戏
- 13个帮你提高开发效率的现代CSS框架
- 快速上手BootstrapVue
- JavaScript引擎是如何工作的?从调用栈到Promise你需要知道的一切
- WebSocket实战:在 Node 和 React 之间进行实时通信
- 关于 Git 的 20 个面试题
- 深入解析 Node.js 的 console.log
- Node.js 究竟是什么?
- 30分钟用Node.js构建一个API服务器
- Javascript的对象拷贝
- 程序员30岁前月薪达不到30K,该何去何从
- 14个最好的 JavaScript 数据可视化库
- 8 个给前端的顶级 VS Code 扩展插件
- Node.js 多线程完全指南
- 把HTML转成PDF的4个方案及实现
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。