如此简单地说,这就是我想要做的事情:
我有一组Range
个连续的对象(非重叠,它们之间没有间隙),每个对象包含一个start
和end
int,以及一个对另一个对象的引用obj
。这些范围不是固定大小(第一个可能是1-49,第二个是50-221等)。这个系列可能会变得非常大。
我希望找到一种方法来查找包含给定数字的范围(或更具体地说,它引用的对象),而不必遍历整个集合,检查每个范围以查看它是否包含该数字。这些查找将经常执行,因此速度/性能是关键。
有谁知道可能会帮助我的算法/等式?我是用Java写的。如果需要,我可以提供更多细节,但我想我会尽量保持简单。
感谢。
答案 0 :(得分:4)
如果您想要使用TreeMap
,其中键是范围的底部,而值是Range
对象。
然后要确定正确的范围,只需使用floorEntry()
方法快速获取最接近(较小或相等)Range
,其中应包含密钥,如下所示:
TreeMap<Integer, Range> map = new TreeMap<>();
map.put(1, new Range(1, 10));
map.put(11, new Range(11, 30));
map.put(31, new Range(31, 100));
// int key = 0; // null
// int key = 1; // Range [start=1, end=10]
// int key = 11; // Range [start=11, end=30]
// int key = 21; // Range [start=11, end=30]
// int key = 31; // Range [start=31, end=100]
// int key = 41; // Range [start=31, end=100]
int key = 101; // Range [start=31, end=100]
// etc.
Range r = null;
Map.Entry<Integer, Range> m = map.floorEntry(key);
if (m != null) {
r = m.getValue();
}
System.out.println(r);
由于树总是按照底部范围边界的自然顺序排序,因此所有搜索都将处于最差O(log(n))。
您希望在密钥完全超出范围时添加一些健全性检查(例如,当密钥超出地图的末尾时,它会返回地图中的最后一个Range
),但这应该让你知道如何继续。
答案 1 :(得分:1)
假设您查找是最重要的,并且您可以节省O(N)内存和大约O(N ^ 2)预处理时间,算法将是:
ObjectsInRange
,其中包含:范围的开头(int startOfRange
)和一组对象(Set<Object> objects
)ArrayList<ObjectsInRange> oir
,其中包含按ObjectsInRange
startOfRange
Range r
,确保存在ObjectsInRange
(让我们称之为a
和b
),a.startOfRange = r.start
和b.startOfRange = b.end
。然后,对于ObjectsInRange x
之间的所有a
,以及直到(但不包括)b
,r.obj
添加x.objects
集然后,查找如下:
x
,找到i
和oir[i].startOfRange <= x
oir[i+1].startOfRange > x
i
!oir[i].objects
答案 2 :(得分:0)
如果集合是有序的,那么您可以实现二进制搜索以在O(log(n))时间内找到正确的范围。对于非常大的集合,它不如散列效率高,但如果你的范围小于1000,它可能会更快(因为它更简单)。