队列
队列是遵循先进先出(FIFO,也称为先来先服务)原则的一组有序的项。队列在尾部添加新元素,并从顶部移除元素。最新添加的元素必须排在队列的末尾。
1. 基于数组实现队列
class Queue {
constructor() {
this.items = [];
}
enqueue(element) {
this.items.push(element);
}
dequeue() {
// shift在数组头部删除元素,后面的元素都会向前移动一位,性能较差
return this.items.shift();
}
peek() {
return this.items[0];
}
isEmpty() {
return this.size() === 0;
}
size() {
return this.items.length;
}
toString() {
if(this.isEmpty()) return '';
let objString = `${this.items[0]}`;
for (let i = 1; i < this.items.length; i++) {
objString = `${objString} , ${this.items[i]}`;
}
return objString;
}
}
2. 基于对象实现队列
class Queue {
constructor() {
this.items = {}; // 保存元素
this.count = 0; // 记录元素的位置
this.minCount = 0; // 记录元素的起始位置
}
// 入队
enqueue(val) {
if (val == null) return;
this.items[this.count++] = val;
}
// 出队
dequeue() {
if (this.isEmpty()) return undefined;
const val = this.items[this.minCount];
delete this.items[this.minCount];
this.minCount++; // 起始位置向后移动一位
return val;
}
peek() {
if (this.isEmpty()) return undefined;
return this.items[this.minCount]
}
size() {
return this.count - this.minCount;
}
isEmpty() {
return this.size() === 0;
}
clear() {
this.items = {};
this.minCount = 0;
this.count = 0;
}
toString() {
if (this.isEmpty()) return '';
let str = `${this.items[this.minCount]}`;
for (let i = this.minCount + 1; i < this.count; i++) {
str = `${str}, ${this.items[i]}`;
}
return str;
}
}
3. 基于链表实现队列
// 链表节点类
class ListNode {
constructor(val) {
this.val = val;
this.next = null; // 指向下一个节点,默认为空
}
}
class Queue {
constructor() {
this.head = null; // 指向队列头节点
this.tail = null; // 指向队列尾节点
this.len = 0; // 记录队列大小,避免遍历链表获取,否则时间复杂度过高
}
enqueue(val) {
const node = new ListNode(val);
// 队列为空
if (this.head == null) {
// 此时头节点和尾节点指向同一个节点
this.head = node;
this.tail = node;
} else {
// 在队尾添加节点
this.tail.next = node;
// 将tail指向新加的节点,也就是最后一个节点
this.tail = this.tail.next;
}
// 队列大小增加1
this.len++;
}
dequeue() {
// 队列为空
if (this.isEmpty()) return null;
// 取头节点,队列要从头部删除元素
const node = this.head;
// 头节点的值
const val = node.val;
// 头指针指向下一个节点,就删除了上一个节点
this.head = this.head.next;
// 队列大小减一
this.len--;
return val;
}
peek() {
if(this.isEmpty()) return null;
return this.head.val;
}
size() {
return this.len;
}
isEmpty() {
return this.size() === 0;
}
toString() {
if(this.isEmpty()) return '';
let str = `${this.head.val}`;
let node = this.head.next;
while(node) {
str = `${str}, ${node.val}`;
node = node.next;
}
return str;
}
}
// 测试代码
const queue = new Queue();
queue.enqueue(10)
queue.enqueue(20)
queue.enqueue(30)
console.info('size1:',queue.size());
console.info('peek1:',queue.peek());
console.info('toString1:',queue.toString());
queue.dequeue()
console.info('size2:',queue.size());
console.info('peek2:',queue.peek());
console.info('toString2:',queue.toString());
queue.dequeue()
console.info('size3:',queue.size());
console.info('peek3:',queue.peek());
console.info('toString3:',queue.toString());
queue.dequeue()
console.info('size4:',queue.size());
console.info('peek4:',queue.peek());
console.info('toString4:',queue.toString());
结果:
三种实现方式的性能测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>队列三种实现方式性能测试</title>
</head>
<body>
<script src="./queue_with_array.js"></script>
<script src="./queue_with_object.js"></script>
<script src="./queue_with_listnode.js"></script>
<script>
const q1 = new Queue_arr();
console.time('queue with array')
for (let i = 0; i < 10 * 10000; i++) {
q1.enqueue(i)
}
for (let i = 0; i < 10 * 10000; i++) {
q1.dequeue()
}
console.timeEnd('queue with array')
const q2 = new Queue_obj();
console.time('queue with object')
for (let i = 0; i < 10 * 10000; i++) {
q2.enqueue(i)
}
for (let i = 0; i < 10 * 10000; i++) {
q2.dequeue()
}
console.timeEnd('queue with object')
const q3 = new Queue_list();
console.time('queue with list')
for (let i = 0; i < 10 * 10000; i++) {
q3.enqueue(i)
}
for (let i = 0; i < 10 * 10000; i++) {
q3.dequeue()
}
console.timeEnd('queue with list')
</script>
</body>
</html>
测试结果:
由此可见,基于数组的实现性能最差,原因是shift()时间复杂度为O(n),故而影响了性能。但是实际工作中如果只是想使用队列的逻辑功能(先进先出),还是推荐使用数组的。