Javascript 有效地查找某个数字范围内的对象

Javascript 有效地查找某个数字范围内的对象,javascript,algorithm,loops,time,Javascript,Algorithm,Loops,Time,这是我的基本问题:我得到了一个currentTime。例如,750秒。我还有一个数组,其中包含1000到2000个对象,每个对象都有一个startTime,endTime,以及一个\u id属性。给定currentTime,我需要找到具有startTime和endTime的对象,该对象在该范围内——例如,startTime:740,endTime:755 在Javascript中最有效的方法是什么 首先,我只是做了一些类似的事情: var arrayLength = array.length;

这是我的基本问题:我得到了一个
currentTime
。例如,750秒。我还有一个数组,其中包含1000到2000个对象,每个对象都有一个
startTime
endTime
,以及一个
\u id
属性。给定
currentTime
,我需要找到具有
startTime
endTime
的对象,该对象在该范围内——例如,
startTime:740
endTime:755

在Javascript中最有效的方法是什么

首先,我只是做了一些类似的事情:

var arrayLength = array.length; 
var x = 0;
while (x < arrayLength) {
 if (currentTime >= array[x].startTime && currentTime <= array[x].endTime) {
  // then I've found my object
 }
x++;
};

听起来像是一个问题。

假设您的搜索数组是长期存在且相对恒定的,第一次迭代将按开始时间对所有数组元素进行排序(或者创建一个已排序的开始时间索引,如果不希望排序,则指向数组元素)

然后,你可以有效地(用二进制印章)折扣那些开始太晚的。然后,依次搜索其他对象会更快

为了获得更高的速度,请为开始时间和结束时间维护单独的排序索引。然后执行前面提到的相同操作,以丢弃那些开始太晚的

然后,对于剩下的那些,使用结束时间索引扔掉那些结束得太早的,剩下的就是你的候选名单


但是,确保这是实际需要的。两千个元素看起来并不是一个很大的数量,所以你应该对当前的方法进行计时,只有在确实存在问题的情况下才尝试优化。

根据给出的信息,不可能判断什么是最佳解决方案。如果数组未排序,循环是单个查询的最佳方式。沿数组的单次扫描只需要O(N)(其中N是数组的长度),而排序然后进行二进制搜索需要O(N log(N)+log(N)),因此在这种情况下需要更多的时间

如果在同一个大数组上有大量不同的查询,则分析结果将大不相同。如果在同一个数组上有大约N个查询,排序实际上可能会提高性能,因为每个查询都需要O(log(N))。因此,对于N个查询,它需要O(N log(N))(剩余的日志(N)现在被删除),而未排序的搜索也需要O(N^2),这显然更大。排序何时开始产生影响还取决于数组的大小

当您相当频繁地更新阵列时,情况也会有所不同。更新未排序的数组可以在O(1)摊销中完成,而更新排序的数组需要O(N)。因此,如果您有相当频繁的更新,排序可能会造成伤害


对于范围查询,也有一些非常有效的数据结构,但是,如果它们有意义与否,则取决于实际使用情况

解决此问题的最佳方法取决于调用搜索函数的次数

如果只调用函数几次,比如说
m次
,那么就进行线性搜索。此函数调用的总体复杂性为
O(mn)

如果多次调用函数,我所说的多次是指超过
log(n)
次,您应该:

  • 如果有多个项目的
    startTime

  • 使用
    startTime查找元素范围如果数组未排序,则您的方法是正确的

    不要陷入先对数组排序,然后应用搜索的思维陷阱

    对于您尝试的代码,您的复杂性为O(n),其中n是元素的数量

    如果首先对数组进行排序,则在
    平均情况下,首先会陷入复杂性O(n log(n))(与之相比)

    然后,您必须应用二进制搜索,它以O(log_2(n)-1)的平均复杂度执行

    因此,在一般情况下,你最终会花费:

    O(n日志(n)+(日志2(n)-1))

    An是一种数据结构,它不只是O(n)

    An,而是允许在O(lg n)时间内(平均和最坏情况下)回答此类查询,前提是总共有n个间隔。构造数据结构的预处理时间为O(nlgn);空间是O(n)。对于间隔树,插入和删除时间为O(lgn)。如果m个区间覆盖一个点,则回答所有区间查询的时间为O(m+lgn)。描述了几种区间树;例如,居中间隔树是三级树,每个节点存储:

    •中心点
    •指向另一个节点的指针,该节点包含完全位于中心点左侧的所有间隔
    •指向另一个节点的指针,该节点包含完全位于中心点右侧的所有间隔
    •所有重叠中心点的间隔,按其起点排序
    •所有重叠中心点的间隔,按其终点排序

    注意,对于找到一个区间覆盖一个点的平均和最坏情况查询,区间树的复杂度都是O(lgn)。对于相同的问题,前面的答案的最坏情况查询性能为O(n)。之前的几个答案声称它们的平均时间为O(lgn)。但他们都没有提供证据;相反,他们只是断言平均性能为O(lgn)。前面这些答案的主要特点是使用二进制搜索开始时间。然后一些人说使用线性搜索,另一些人说使用二进制搜索,用于结束时间,但没有明确后一种搜索结束的时间间隔集。他们声称拥有O(lgn)的平均性能,但这只是一厢情愿。正如维基百科文章所指出的
    var binarySearch = function(array, currentTime) {
    
      var low = 0;
      var high = array.length - 1;
      var i; 
    
      while (low <= high) {
        i = Math.floor((low + high) / 2);
    
        if (array[i].startTime <= currentTime) {
    
          if (array[i].endTime >= currentTime ){
            // this is the one
            return array[i]._id; 
    
          } else {
            low = i + 1;
          }
        }
    
        else {
          high = i - 1;
        }
      } 
    
      return null;
    }