插入要比数组还快的数据结构

62 阅读2分钟

「我正在参与掘金会员专属活动-源码共读第一期,点击参与

本篇文章介绍的是yocto-queue,一个微型队列的数据结构。

数组在做向前插入unshift删除shift时间复杂度为O(n),而队列仅仅是O(1)。如果需要频繁进行操作的话,推荐队列作为数据存储的首选。

安装

$ npm install yocto-queue

使用

import Queue from 'yocto-queue';

const queue = new Queue();

queue.enqueue('🦄');
queue.enqueue('🌈');

console.log(queue.size);
//=> 2

console.log(...queue);
//=> '🦄 🌈'

console.log(queue.dequeue());
//=> '🦄'

console.log(queue.dequeue());
//=> '🌈'

API

queue = new Queue()

实例是一个可迭代对象,这就是说你可以使用for..of循环迭代它,或者可以使用展开符将它转换成数组,不要这么做,因为这样很慢。

.enqueue(value)

向队列中添加元素

.dequeue()

移除队列中的元素,并返回该值,如果队列为空,返回undefined

.clear()

清空队列

.size

返回队列大小

源码

class Node {
	value;
	next;

	constructor(value) {
		this.value = value;
	}
}

这个是队列中元素的数据结构


export default class Queue {
	#head; 
	#tail;
	#size;

	constructor() {
		this.clear();
	}

	enqueue(value) {
		const node = new Node(value);

		if (this.#head) {
			this.#tail.next = node;
			this.#tail = node;
		} else {
			this.#head = node;
			this.#tail = node;
		}

		this.#size++;
	}

	dequeue() {
		const current = this.#head;
		if (!current) {
			return;
		}

		this.#head = this.#head.next;
		this.#size--;
		return current.value;
	}

	clear() {
		this.#head = undefined;
		this.#tail = undefined;
		this.#size = 0;
	}

	get size() {
		return this.#size;
	}

	* [Symbol.iterator]() {
		let current = this.#head;

		while (current) {
			yield current.value;
			current = current.next;
		}
	}
}

这个是队列的数据结构。

  • #head:队列的头部 #tail:队列的尾部 #size 队列的长度
  • enqueue: 入队操作(向队列添加元素)。首先会根据传入的value构造出node,如果头部存在,就向#tail本身和它的next属性赋值为node,如果不存在#head,头部和尾部都赋值为node

GIF 2022-12-6 11-57-31.gif

  • dequeue:如果存在#head,将#headnext属性赋值为#head,返回原来头部的值。否则返回undefined

  • clear: 将#head #tail置空,#size设置为0

  • 自定义一个迭代器:* [Symbol.iterator]()

GIF 2022-12-6 12-07-10.gif

测试用例

测试用例使用的是ava这个包,它默认导出test方法,可以传入测试自定义名字,和一个回调函数,回调函数接收到一个参数为t来校验测试结果

test('.enqueue()', t => {
	const queue = new Queue();
	queue.enqueue('🦄');
	t.is(queue.dequeue(), '🦄');
	queue.enqueue('🌈');
	queue.enqueue('❤️');
	t.is(queue.dequeue(), '🌈');
	t.is(queue.dequeue(), '❤️');
});

通常我们在开发某个功能的时候可以先把所有的测试用例写出来,然后运行测试,等到所有的测试用例都跑通了,我们的功能也就开发完了。

结束语

这篇文章介绍的队列在插入和删除方面优势确实是比数组的性能高,但是在取值方面是不如数组的,数组在取值O(1)的复杂度。所以我们在平时选择数据结构还得看实际是怎么应用的。