这就是 oldestIndex 和 newestIndex 这两个属性 在队列中的用途。所有这一切似乎令人困惑——到现在我仍然会偶尔觉得困惑。下面的例子可以帮助我门理顺所有的逻辑。
假设我们的熟食店有两个售票系统:
_newestindex 代表顾客售票系统的票。
_oldestindex 代表员工售票系统的票。
对于两个售票系统来说,这是最难掌握的概念:当两个系统中的数字相同时,队列中的每个客户都被处理了,队列是空的。我们将使用下面的场景来加强这种逻辑:
当顾客买票时,顾客的票号从_newestIndex 得到,票的编号是1。顾客售票系统的下一张票号码是2。
员工不买票,员工售票系统中当前票的编号是1。
我们在顾客系统中得到当前的票号2,减去员工系统中的号码1,得到的结果是1。这个数字1表示仍然在队列中没有被删除的票的数量
员工从它们的售票系统中取票,这张票代表正在被服务的顾客的票号,从_oldestIndex中得到,数字为1。
重复第4步,现在差为0,队列中没有其他的票了。
现在属性 _newestindex可以告诉我们被分配在队列中票号的最大值(键),属性 _oldestindex 可以告诉我们最先进入队列中票号(键)。
探讨完了size(),接下来看enqueue(data)方法。
方法2/3:enqueue(data)
对于 enqueue 方法,有两个功能:
使用_newestIndex 的值作为 this._storage 的键,并使用要添加的数据作为该键的值。
将_newestIndex 的值增加1。
基于这两个功能,我们将编写 enqueue(data) 方法的代码:
Queue.prototype.enqueue = function(data) { this._storage[this._newestIndex] = data; this._newestIndex++; };
该方法的主体只有两行代码。 在第一行,用 this._newestIndex 为this._storage 创建一个新的键,并为其分配数据。 this._newestIndex 始终从1开始。在第二行代码中,我们将 this._newestIndex 的值增加1,将其更新为2。
以上是方法 enqueue(data) 的所有代码。下面我们来实现方法 dequeue( )。
方法2/3:dequeue( )
以下是此方法的两个功能点:
删除队列中最旧的数据。
属性 _oldestIndex 加1。
Queue.prototype.dequeue = function() { var oldestIndex = this._oldestIndex, deletedData = this._storage[oldestIndex]; delete this._storage[oldestIndex]; this._oldestIndex++; return deletedData; };
在 dequeue( )的代码中,我们声明两个变量。 第一个变量 oldestIndex 给 this._oldestIndex 赋值。第二个变量 deletedData 被赋予 this._storage[oldestIndex] 的值。
下一步,删除队列中最早的索引。之后将 this._oldestIndex 的值加1。最后返回刚刚被删除的数据。
与栈的 pop() 方法第一次实现中出现的问题类似,dequeue() 在队列中没有数据的情况下不应该被执行。我们需要一些代码来处理这种情况。
Queue.prototype.dequeue = function() { var oldestIndex = this._oldestIndex, newestIndex = this._newestIndex, deletedData; if (oldestIndex !== newestIndex) { deletedData = this._storage[oldestIndex]; delete this._storage[oldestIndex]; this._oldestIndex++; return deletedData; } };
每当 oldestIndex 和 newestIndex 的值不相等时,我们就执行前面的逻辑。
队列的完整实现代码
到此为止,我们实现了一个完整的队列结构的逻辑。下面是全部代码。
function Queue() { this._oldestIndex = 1; this._newestIndex = 1; this._storage = {}; } Queue.prototype.size = function() { return this._newestIndex - this._oldestIndex; }; Queue.prototype.enqueue = function(data) { this._storage[this._newestIndex] = data; this._newestIndex++; }; Queue.prototype.dequeue = function() { var oldestIndex = this._oldestIndex, newestIndex = this._newestIndex, deletedData; if (oldestIndex !== newestIndex) { deletedData = this._storage[oldestIndex]; delete this._storage[oldestIndex]; this._oldestIndex++; return deletedData; } };
结束语
在本文中,我们探讨了两个线性数据结构:栈和队列。栈按照顺序存储数据,并删除最后添加的数据;队列按顺序存储数据,但删除最先的添加数据。
如果这些数据结构的实现看起来微不足道,请提醒自己数据结构的用途。它们并没有被设计得过于复杂,它们是用来帮助我们组织数据的。在这种情况下,如果您发现有需要按顺序组织数据的场合,请考虑使用栈或队列。