我在Javascript中有一个对象数组,其中包含一个以毫秒为单位的事件开始和结束时刻。我们的代码库目前使用一种天真的搜索算法,该算法遍历数组,直到我们找到包含某个时刻的事件:
// time contains the moment of time we're looking to find an event for
profile.tempbasaltreatments.forEach( function eachTreatment (t) {
if (time <= t.endmills && time >= t.mills) {
return t;
}
});
没有使用较大数据集的性能来削减它。什么是一个好的算法/数据模型,可以有效地通过对象数组来查找封装时刻的事件?您可以假设,如果事件重叠,第一次匹配总是足够的。
答案 0 :(得分:2)
我会建议这些预处理步骤(搜索之前):
然后搜索将是二进制的,如下所示:
预处理应该只进行一次,如果你仍然需要排序,它的时间复杂度 O(n log n),否则它是 O(n)。完成后,您可以在 O(log n)时间内重复查找事件。
以下是上面的一些JavaScript代码:
// Create a copy of the original array and sort it by event start date
var events = profile.tempbasaltreatments.slice(0).sort(function (a, b) {
return a.mills - b.mills;
});
// Remove events that fall completely within the limits of another event.
// They are not needed to find an event for a given time.
for (var i = 0; i < events.length-1;) {
if (i && events[i].endmills < events[i-1].endmills) {
events.splice(i, 1);
} else {
i++;
};
}
// Now also the remaining events' end dates are sorted
// function for fast search in events:
function findEvent(events, time) {
// Binary search for event
var first = 0, last = events.length - 1;
while (first <= last) {
var i = first + Math.floor((last - first) / 2);
var t = events[i];
if (time >= t.mills && time <= t.endmills) return t;
if (time < t.mills) {
last = i - 1;
} else { // time > t.endmills
first = i + 1;
}
}
// returns undefined
}
// Example call: find a currently running event:
var foundEvent = findEvent(events, new Date().getTime());
以下是在最后一个预处理步骤中进行过滤的方法。首先是在开始时间排序后如何排序事件的时间表:
a: ---------------
b: -------
c: ------------------
d: --
e: --
f: -----
可以消除的事件是b:
a: ---------------
c: ------------------
d: --
e: --
f: -----
....然后d:
a: ---------------
c: ------------------
e: --
f: -----
...然后e:
a: ---------------
c: ------------------
f: -----
...和f:
a: ---------------
c: ------------------
很明显,在过滤之前,总覆盖期与原始期相同。
答案 1 :(得分:0)
如果事件按开始时间,“中间时间”或结束时间排序,您可以使用二进制搜索来查找附近的事件,然后执行本地线性搜索以查找包含时间戳的内容(本地搜索)方向取决于排序顺序:如果事件按开始时间排序,则需要查看从最近的开始时间开始减少开始时间的方向。
这种方法的主要问题是当没有最大事件持续时间时它很慢,因为这意味着除了到达列表末尾之外没有本地搜索的停止标准。
更好的方法可能是将事件存储在适合高效访问的数据结构中,例如:一个interval tree。