Java中的范围查找 [英] Range lookup in Java
问题描述
假设我有一个未排序的重叠数组范围
。每个范围
只是一对整数 begin
和 end
。现在我想查找给定的密钥
是否属于至少一个范围
。也许我必须知道它所属的范围
。
Suppose, I have an unsorted array of overlapped ranges
. Each range
is just a pair of integers begin
and end
. Now I want to find if a given key
belongs to at least one of the ranges
. Probably, I have to know the ranges
it belongs as well.
我们可以假设 range
array需要〜1M并适合内存。我正在寻找一种简单的算法,它只使用标准的JDK集合,而不需要任何3d方式的库和特殊的数据结构,但是工作速度相当快。
We can assume the ranges
array takes ~1M and fits the memory. I am looking for an easy algorithm, which uses only standard JDK collections without any 3d-party libraries and special data structures, but works reasonably fast.
你会建议什么?
推荐答案
如果您不需要知道 间隔包含您的观点(编辑:我猜你可能会这样做,但是我会把这个答案留给这个问题的人,而不是那个),然后
If you don't need to know which interval contains your point ( I guess you probably do, but I'll leave this answer for others with this question who don't), then
-
预处理通过计算两个数组B和E的间隔.B是以排序顺序开始的值。 E是以排序顺序结束的值。
Preprocess the intervals by computing two arrays B and E. B is the values of begin in sorted order. E is the values of end in sorted order.
要查询点x,请使用二叉搜索找到最小索引i,使得B [i]> x和最小索引j使得E [j]≥x。包含x的间隔数[begin,end]为i - j。
To query a point x, use binary search to find the least index i such that B[i] > x and the least index j such that E[j] ≥ x. The number of intervals [begin, end] containing x is i - j.
class Interval {
double begin, end;
}
class BeginComparator implements java.util.Comparator<Interval> {
public int compare(Interval o1, Interval o2) {
return Double.compare(o1.begin, o2.begin);
}
};
public class IntervalTree {
IntervalTree(Interval[] intervals_) {
intervals = intervals_.clone();
java.util.Arrays.sort(intervals, new BeginComparator());
maxEnd = new double[intervals.length];
initializeMaxEnd(0, intervals.length);
}
double initializeMaxEnd(int a, int b) {
if (a >= b) {
return Double.NEGATIVE_INFINITY;
}
int m = (a + b) >>> 1;
maxEnd[m] = initializeMaxEnd(a, m);
return Math.max(Math.max(maxEnd[m], intervals[m].end), initializeMaxEnd(m + 1, b));
}
void findContainingIntervals(double x, int a, int b, java.util.Collection<Interval> result) {
if (a >= b) {
return;
}
int m = (a + b) >>> 1;
Interval i = intervals[m];
if (x < i.begin) {
findContainingIntervals(x, a, m, result);
} else {
if (x <= i.end) {
result.add(i);
}
if (maxEnd[m] >= x) {
findContainingIntervals(x, a, m, result);
}
findContainingIntervals(x, m + 1, b, result);
}
}
java.util.Collection<Interval> findContainingIntervals(double x) {
java.util.Collection<Interval> result = new java.util.ArrayList<Interval>();
findContainingIntervals(x, 0, intervals.length, result);
return result;
}
Interval[] intervals;
double[] maxEnd;
public static void main(String[] args) {
java.util.Random r = new java.util.Random();
Interval[] intervals = new Interval[10000];
for (int j = 0; j < intervals.length; j++) {
Interval i = new Interval();
do {
i.begin = r.nextDouble();
i.end = r.nextDouble();
} while (i.begin >= i.end);
intervals[j] = i;
}
IntervalTree it = new IntervalTree(intervals);
double x = r.nextDouble();
java.util.Collection<Interval> result = it.findContainingIntervals(x);
int count = 0;
for (Interval i : intervals) {
if (i.begin <= x && x <= i.end) {
count++;
}
}
System.out.println(result.size());
System.out.println(count);
}
}
这篇关于Java中的范围查找的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!