【问题标题】:Most computationally efficient method to insert into an ordered array?插入有序数组的计算效率最高的方法?
【发布时间】:2014-01-23 14:28:14
【问题描述】:

我有一个包含时间序列数据的数组,如下所示:

var timeseries = [
    [Tue Dec 31 2013 00:00:00 GMT+0000 (GMT Standard Time), 3, 2],
    [Tue Dec 31 2013 01:00:00 GMT+0000 (GMT Standard Time), 1.2, 3],
    [Tue Dec 31 2013 02:00:00 GMT+0000 (GMT Standard Time), 4, 2]
]

嵌套数组中的第一项是 javascript 日期。

我有第二个数组,其中包含一个唯一的 javascript 日期列表,但 timeseries 数组中可能已经存在也可能不存在:

var newTimes = [
    Tue Dec 31 2013 00:13:00 GMT+0000 (GMT Standard Time), 
    Tue Dec 31 2013 01:00:00 GMT+0000 (GMT Standard Time), 
    Tue Dec 31 2013 01:40:00 GMT+0000 (GMT Standard Time)
]

对于 newTimes 数组中的每个项目,我需要检查该日期是否存在于与 timeseries 数组一起存储的数组中。如果没有,我想在时间序列数组的正确位置(时间顺序)插入一个新数组,并且 - 至关重要的是 - 从前面的数组中复制其他数组值。例如,按照描述组合上述两个数组将产生:

var newTimeseries = [
    [Tue Dec 31 2013 00:00:00 GMT+0000 (GMT Standard Time), 3, 2],
    [Tue Dec 31 2013 00:13:00 GMT+0000 (GMT Standard Time), 3, 2],
    [Tue Dec 31 2013 01:00:00 GMT+0000 (GMT Standard Time), 1.2, 3],
    [Tue Dec 31 2013 01:40:00 GMT+0000 (GMT Standard Time), 1.2, 3],
    [Tue Dec 31 2013 02:00:00 GMT+0000 (GMT Standard Time), 4, 2]
]

我应该注意两个数组都已经排序。此外,newTimes 中的项目将存在于 timeseries 的范围内。最后,原始 timeseries 数组每小时都有一个条目,在整点。

我尝试了几种不同的方法,但我对计算效率最高的方法很感兴趣。如果有帮助,我很乐意使用任何适当的、被广泛采用的第三方库,例如 underscore.js。

【问题讨论】:

  • 想到一个链表...
  • 嗯,一个链表会给你O(1)的插入复杂度和O(n)的搜索复杂度。我想你会发现“最有效”取决于你命中/未命中的频率。
  • 根据列表大小,您可能会插入所有内容,然后遍历列表一次以复制额外数据或删除双重条目。只是在这里集思广益:)
  • 在数组中存储 unix 时间戳而不是日期对象,我想这将有助于加快速度(在查找要插入的正确位置时)
  • 列表的大小会有所不同。通常的用例范围可能是 150 个条目,最多约 4000 个

标签: javascript jquery arrays performance


【解决方案1】:

考虑过二分搜索(由 cmets 中的 techfoobar 建议)和冒泡排序(friendzis),到目前为止我想出的最佳解决方案就是遵循这个逻辑。

与使用二分搜索相反,请考虑以下事项。

因为我们知道两个数组都已经排序了; newTimes 内的日期在timeseries 日期范围内;并且最初的 timeseries 条目是按小时计算的,每小时,我们可以找到 timeseries[0][0] date 和 newTimes[0] 之间的差异(以小时为单位)。这是启动冒泡排序方法所需的初始偏移量(更像是上面 cmets 中讨论的标准循环和切片)。这使用了Moment.js 库。

代码如下,欢迎提出修改建议:

var firstEvent = moment(newTimes[0]);
var firstTime = moment(timeseries[0][0]) ;
var offset = firstEvent.diff(firstTime, 'hours') - 1; 


for (var i = offset; i < timeseries.length;i++) { 
    while (newTimes.length > 0 && typeof moment(timeseries[i+1]) !== "undefined" && moment(newTimes[0])  > moment(timeseries[i][0]) && moment(newTimes[0])  < moment(timeseries[i+1][0])) {
        var newElement = timeseries[i].slice(0);
        newElement[0] = moment(newTimes[0]).toDate();
        timeseries.splice(i+1, 0, newElement);
        newTimes.splice(0,1);
        i++;
    } 
}

重要的是,当newTimes 数组中有两个或多个条目都在一个timeseries 条目中时,这可以处理边缘情况,例如:

var timeseries = [
    [Tue Dec 31 2013 00:00:00 GMT+0000 (GMT Standard Time), 3, 2],
    [Tue Dec 31 2013 01:00:00 GMT+0000 (GMT Standard Time), 1.2, 3]
]

var newTimes = [
    Tue Dec 31 2013 00:13:00 GMT+0000 (GMT Standard Time), 
    Tue Dec 31 2013 00:16:00 GMT+0000 (GMT Standard Time)
]

【讨论】:

    猜你喜欢
    • 2016-09-11
    • 1970-01-01
    • 2019-07-31
    • 2020-12-02
    • 1970-01-01
    • 2021-04-05
    • 2015-01-30
    • 2011-04-20
    • 2011-03-11
    相关资源
    最近更新 更多