add,removeFirst,removeFirstN数组操作的性能优化

时间:2018-02-20 16:06:53

标签: javascript arrays performance

对于我的用例,我发现移位/切片方法过多地压缩了我的CPU,因为数组的大小增加了。理论上,阵列可能大到86400个项目,尽管通常它会低得多 - 大约10000个数组元素。

我试图通过一个简单的例子来说明它。想象一下这个规模非常大。它会一直运行到一定程度,但一般来说,删除这样的第一个(或前n个)项目似乎非常无效。

希望对“为什么会这样”有更多了解的人可以在下面的代码段中填写以下三个函数中的一个或多个:

  • 加()
  • removeFirst()
  • removeFirstN(n)的

不可变性在这里不起作用 - 或者更确切地说,因为我们追求的是最佳性能,复制一个不断增长且相当大的数据结构(在这种情况下是数组)肯定是行不通的。

有什么好建议吗? : - )

let objArray = []
let maxCount = 10;
let i = 0;

function add(){
  objArray.push({x: + new Date(), y: Math.floor(Math.random() * 10000) + 1});
  console.log("add")
}

function removeFirst(){
  objArray.shift();
  console.log("removeFirst")
}

function removeFirstN(n){
  objArray.splice(0,n)
  console.log(`removeFirstN(${n})`)
}

// Every second and obj is added to the array
setInterval(function(){
  if(objArray.length === maxCount){
    removeFirst();
  } else if(objArray.length > maxCount) { // this is possible since we're allowed to change maxCount
    const diff = objArray.length+1 - maxCount;
    removeFirstN(diff);
  }
  // Always add
  add();
  
  i++;
  
  if(i === 15) {
    maxCount--;
    i = 0;
  }
  
  console.log(`length: ${[...objArray].length}`)
  console.log([...objArray])
}, 1000)

1 个答案:

答案 0 :(得分:1)

根据列出的操作判断,您正在寻找一个constant-time入队和出队的队列。通过在一侧移动操作的所有元素将数组用作队列时,该操作需要花费与数组中元素数量成比例的时间。基于循环缓冲区或链表(均满足恒定时间要求)的实现将随着元素数量的增加而更快。

链接列表非常简单,可以在帖子中进行演示:

class LinkedQueue {
    constructor() {
        this.head = null;
        this.tail = null;
    }

    enqueue(value) {
        const node = {value, next: null};

        if (this.tail === null) {
            // Empty queue; make this the only node
            this.tail = this.head = node;
        } else {
            // Make this the successor of the current last node,
            // then make it the new last node
            this.tail = this.tail.next = node;
        }
    }

    dequeue() {
        const result = this.head.value;

        if (this.head === this.tail) {
            // Last element remaining
            this.head = this.tail = null;
        } else {
            // Remove the first element
            this.head = this.head.next;
        }

        return result;
    }
}

但是为了在实践中获得最佳性能,您需要使用基于循环缓冲区的队列。 double-ended-queue是一个这样的npm包。