我有一组整数范围,表示类的下限和上限。例如:
0..500 xsmall
500..1000 small
1000..1500 medium
1500..2500 large
在我的情况下,可以有超过500个课程。这些类不重叠,但它们的大小可能不同。
我可以通过列表实现查找匹配范围作为简单的线性搜索,例如
class Range
{
int lower;
int upper;
String category;
boolean contains(int val)
{
return lower <= val && val < upper;
}
}
public String getMatchingCategory(int val)
{
for (Range r : listOfRanges)
{
if (r.contains(val))
{
return r.category;
}
}
return null;
}
然而,这似乎很慢;因为我需要平均N / 2次观看。如果课程大小相同,我可以使用分工。是否有标准技术可以更快地找到正确的范围?
答案 0 :(得分:3)
您要找的是SortedMap
及其方法tailMap
和firstKey
。查看documentation了解完整详情。
这种方法优于普通数组的优势在于易于维护范围:您可以在任何点插入/删除新边界,几乎没有运行时成本;对于数组,它意味着完全复制两个并行数组。
我为两种变体编写了代码并对其进行了基准测试:
@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class BinarySearch
{
static final int ARRAY_SIZE = 128, INCREMENT = 1000;
static final int[] arrayK = new int[ARRAY_SIZE];
static final String[] arrayV = new String[ARRAY_SIZE];
static final SortedMap<Integer,String> map = new TreeMap<>();
static {
for (int i = 0, j = 0; i < arrayK.length; i++) {
arrayK[i] = j; arrayV[i] = String.valueOf(j);
map.put(j, String.valueOf(j));
j += INCREMENT;
}
}
final Random rnd = new Random();
int rndInt;
@Setup(Level.Invocation) public void nextInt() {
rndInt = rnd.nextInt((ARRAY_SIZE-1)*INCREMENT);
}
@GenerateMicroBenchmark
public String array() {
final int i = Arrays.binarySearch(arrayK, rndInt);
return arrayV[i >= 0? i : -(i+1)];
}
@GenerateMicroBenchmark
public String sortedMap() {
return map.tailMap(rndInt).values().iterator().next();
}
}
基准测试结果:
Benchmark Mode Thr Cnt Sec Mean Mean error Units
array thrpt 1 5 5 10.948 0.033 ops/usec
sortedMap thrpt 1 5 5 5.752 0.070 ops/usec
解释:数组搜索速度只有两倍,而且这个因素在数组大小上非常稳定。在给出的代码中,数组大小为1024,因子为1.9。我还测试了数组大小为128,其中因子为2.05。
答案 1 :(得分:1)
在这里,Arrays.binarySearch
是你的朋友。简单地将所有边界放入并处理可能的情况。假设你的范围在它们之间没有留下任何空洞,你只需要将上限放在。
对于你的例子
0..500 xsmall
500..1000 small
1000..1500 medium
1500..2500 large
你要用
int[] boundaries = {500, 1000, 1500, 2500};
并查看输入。处理这两个案例(找到/未找到),你就完成了。忘记范围,他们很好,但他们不适合你的问题。
我还写了一个benchmark,无论我如何尝试,我都会失去我的赌注,因为比率约为3而不是5.我results中的S001024
等奇怪的事情代表1024的大小。