【问题标题】:Fastest way to iterate through the oldest items in an array? (Fastest implementation of a queue)迭代数组中最旧项目的最快方法? (队列的最快实现)
【发布时间】:2021-04-20 02:42:31
【问题描述】:

也见编辑

我正在使用 JavaScript,但任何类型的可读伪代码都可以回答我的问题。

我将很难描述这一点,所以请随时发表评论澄清 - 我会回答他们并相应地完善我的帖子。

本质上,我有一个充当队列的数组,添加项目,在处理它们时需要删除它们,最终会添加更多。当我不关心索引时,获取数组中第一项的最快方法是什么?我只想在第一次添加的基础上进行迭代,而不必每次都向下移动数组中的所有条目。另外值得一提的是,我没有遍历数组,我的应用程序有一个主循环,用于检查数组是否在每个循环上都有项目,如果有,它将获取该数据然后将其从数组中删除。目前为了快速做到这一点,我使用 pop,但现在认识到我每次都需要首先获取队列中最旧的项目,而不是最新的。

如果需要更多说明:

在我的应用程序中,我有原始数据块,首先需要通过一个函数运行这些数据块,以便准备好供我的应用程序的其他部分使用。每个块都有一个唯一的 ID,我将其传递给函数以便对其进行解析。出于优化目的,我只在需要时解析数据块。

为了做到这一点,我当前的系统是当我意识到我需要解析一个块时,我将它的唯一 ID 推送到一个数组中,然后我的应用程序中的一个连续循环不断检查所述数组,查看它是否有项目在里面。如果是,它会弹出数组的最后一项并将唯一的 id 传递给解析函数。

出于性能原因,在循环的每次迭代中,只能解析一个数据块。当多个数据块已经在队列数组中时,就会出现问题,并且我在循环完成将数组中已经存在的 ID 传递给函数之前向数组添加了更多项。基本上,需要解析的新 ID 会在我的循环清除它们之前添加到数组的末尾。

现在,这还不算太糟糕,因为需要的新数据有点稀少,但是当它需要时,会同时添加很多 ID,这是我无法真正更改的应用程序的属性。

由于我使用的是pop,显然总是首先解析最近添加的ID,但我选择了这种方法,因为我认为它是迭代这样一个队列的最快方法。但是,我开始意识到我宁愿先解析列表中最旧的项目。

本质上,我正在寻找一种方法来循环遍历从最旧到最新的数组,而不必每次都重新组织数组。数组的索引不重要,我只需要先添加,先解析的行为。

例如,我知道我总是可以将数组中的第 0 项传递给我的函数,然后将其余的项向下移动,但是,我认为必须向下移动数组中的其余项成本太高性能,并不值得。如果我只是愚蠢并且应该没有实际成本,请告诉我,但这似乎仍然是一种创可贴。我敢肯定那里有更好的解决方案。

我也对其他数据结构持开放态度,因为数组只包含字符串。

谢谢

编辑:在进行更多的谷歌搜索时,我遇到了一个掌心时刻,并意识到我所描述的问题是堆栈与队列。但是现在我的问题转移到当索引对我没有真正价值时,最快的队列实现是什么?

【问题讨论】:

  • 一个带有头部索引的数组不适合您的目的?
  • @HWSiew 如果我对什么是头索引的理解是正确的,那么不,因为我将清除数组,并且它会在很长一段时间内为空,直到添加批次。出于这个原因,我不一定看到跟踪索引的简单方法。
  • hmm.. 如果您能详细说明,我有点困惑。队列是一种先进先出的数据结构。队列的头索引为空时为空,并且头索引仅在添加第一项或删除一项时更新。这应该是使用 add() 和 remove() 的非常简单的操作
  • 但是,这种方法可能会使用更多空间,因为实际上没有从数组中删除任何项目。另一种方法是使用链表实现队列。
  • FIFO 正是我所需要的,也许我在上面弄糊涂了。假设我添加了 10 个新项目,订购项目 1 到 10。目前项目 10 被处理并首先弹出,但我需要项目 1 首先处理和删除。我了解 shift 方法可以做到这一点,但我不一定需要重新索引数组。我认为会有比这更好的解决方案。

标签: javascript arrays loops queue iteration


【解决方案1】:

以下是javascript中使用单链表的FIFO队列实现。

更多链表信息->https://www.geeksforgeeks.org/linked-list-set-1-introduction/

// queue implementation with linked list
var ListNode = function(val,next = null){
  
  this.val  = val 
  this.next = next

};

var Queue = function(){
  
  let head = null;
  let tail = null;
  
  this.show = function(){
    
    let curr = head;
    let q = [];
    
    while(curr){
      q.push(curr.val);
      curr = curr.next;
    }
    
    return q.join(' -> ');
  }
  
  this.enqueue = function(item){
    
    let node = new ListNode(item);
    if(!head) {
      head = node;
      tail = node;
    } else {
      tail.next = node;
      tail = node;
    }
    
  }
  
  this.dequeue = function(){
    
    if(!head) return null;
    else {
    
      let first = head;
      head = head.next;
      
      first.next = null;
      
      return first;
    }
    
  }
  
}

var myQueue = new Queue();
myQueue.enqueue(1); // head -> 1 
console.log(myQueue.show())
myQueue.enqueue(2); // head -> 1 -> 2
console.log(myQueue.show())
myQueue.enqueue(3); // head -> 1 -> 2 -> 3
console.log(myQueue.show())
myQueue.dequeue(); // head -> 2 -> 3
console.log(myQueue.show())

【讨论】:

  • 我会将此标记为答案,因为它可以工作并且从我的快速 jsbench 中快速运行,但上面 cmets 中的包实际上更快,所以我最终选择了它。感谢您的帮助!
猜你喜欢
  • 2012-12-31
  • 1970-01-01
  • 1970-01-01
  • 2017-02-23
  • 1970-01-01
  • 2013-10-01
  • 2022-06-13
  • 2021-09-12
  • 2019-04-08
相关资源
最近更新 更多