这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战
介绍
队列是计算机科学常用的数据结构,当然我们的生活中也是的,它遵循先进先出的原则,比如安排任务就会说加入任务队列,再比如网页的新手引导队列,本期我们就会用普通对象的形式而非数组的形式,手写一个队列的类出来,加深我们的理解。
概念
队列是遵循先进先出(FIFO,也称为先来先服务)原则的一组有序的项。队列在尾部添加新元素,并从顶部移除元素。最新添加的元素必须排在队列的末尾。
正文
1.基础结构
我们先看一下,要实现的大体结构与其方法:
const items = new WeakMap();
const count = new WeakMap();
const delCount = new WeakMap();
class Queue {
constructor() {
items.set(this, {})
count.set(this, 0)
delCount.set(this, 0)
return this;
}
size() {}
get(){}
enqueue(item) { }
dequeue() {}
peak() {}
clear() {}
}
export default Queue;
我们使用WeakMap这个ES6新数据结构来完成队列的私有变量了,保护其内部的参数不被外界破坏。我们在这里创建三个私有变量分别为items元素存储器与count计数器还有delCount删除收集计数器,至于后面的几个方法为:
-
size:返回当前队列的元素个数。
-
get:返回一个当期队列所有元素和长度值。
-
enqueue:向队列尾部添加一个元素,返回其当前。
-
dequeue:移除队列的第一项,并返回其元素。
-
peek:返回队列中第一个元素。
-
clear:清除队列所有的元素。
接下来我们逐个说一下,怎么来实现。
2.size&get&clear
size() {
return count.get(this) - delCount.get(this);
}
get(){
return {
...items.get(this),
length:this.size()
}
}
clear() {
items.set(this, {});
count.set(this, 0);
delCount.set(this, 0);
}
size这里去做队列的长度计算,因为队列是先进先出的的,移走后始终会出现缺省值,比如下标为0一旦移走了,那么下标为0的永远没有了,下次进入队列的值就是1做下标了,那么长度就不能单纯依靠计数器count去完成了,所以我们期望当一个元素从队列移除后,那么delCount做计数加一,再让两个计数器做差,这样就能得到整个队列的长度了。这个可以往后对比dequeue方法去观察。
至于,get方法,我们仅仅去为了方便我们本次查看元素的变化,所以返回了元素和长度两个信息。clear为完全情况当前的元素和计数器,这里也不做赘述。
3.enqueue
enqueue(item) {
let _items = items.get(this);
let _count = count.get(this);
_items[_count] = item;
_count += 1;
items.set(this, _items);
count.set(this, _count);
return this.size();
}
enqueue是向队列尾部添加一个元素,类似于数组中的push。将传入的元素注入到元素集合中,同时改变计数器。并用刚才size方法获取并返回当前队列长度。
4.dequeue&peek
dequeue() {
if (this.size() == 0) return undefined;
let _items = items.get(this);
let _delcount = delCount.get(this);
let item = _items[_delcount];
delete _items[_delcount];
delCount.set(this,_delcount+1)
return item;
}
peak() {
if (this.size() == 0) return undefined;
return items.get(this)[delCount.get(this)];
}
dequeue和peak都是拿他第一个元素,我们用delCount去拿取,如果当前没有元素移除他自然就是0,每当移除一个就要加一,那么队列第一个值得下标就是他delCount的当前值了。
5.使用&结果
import Queue from "./js/Queue"
const queue= new Queue();
console.log('enqueue->',queue.enqueue(1));
console.log('enqueue->',queue.enqueue(2))
console.log('enqueue->',queue.enqueue(3))
console.log('get->',queue.get());
console.log("---------------")
console.log('peak->',queue.peak())
console.log('get->',queue.get());
console.log("---------------")
console.log('dequeue->',queue.dequeue())
console.log('get->',queue.get());
console.log("---------------")
console.log('clear->',queue.clear());
console.log('get->',queue.get());
-
'enqueue推入队列三条数据,看看数据的变化。
-
peak方法查看当前队列的首个元素。
-
dequeue方法移除队列里首个元素,并返回,与peak作对比看数据变化。
-
clear情况数据,观察数据变化。
我们发现结果都是符合期望的,这样我们就用js普通对象模拟出了一个受保护的队列,遵循了先进先出的原则。
结语
本次我们学习实现了队列这一最基础的数据结构。其实队列在我们生活中也极为常见,比如在学校,电影院,门禁打卡,打印文件,我们都会排队。排在第一位的人会先接受服务,然后一个一个的进行服务,直到服务结束。在前端应用里,有这种业务,比如好多弹框业务,或者引导业务,都可以使用它或它的思想。