我有一个矩形列表,以通常的方式创建:
List<Rectangle> rects = new ArrayList<>();
添加了一些矩形(所有矩形都具有非零宽度和高度)。列表包含的矩形数可以是0到10,000之间的任何值,通常介于4,000到6,000之间。
列表按矩形原点的升序X坐标排序,然后按重复X坐标的Y坐标排序(尽管两个或多个具有相同X坐标的矩形很少)。
我已经验证了排序正确完成(我使用带有自定义比较器的Collections.sort)。
我需要一个方法,将输入两个整数,x和y作为输入,并返回包含点(x,y)的第一个Rectangle,如果列表中没有Rectangle包含该点,则返回null。
public Rectangle findContainingRectangle(int x, int y)
天真的方法确实提供了所需的功能,它只是遍历列表并在每个Rectangle上调用contains方法,但这太慢了。
列表将在程序运行时被修改,但与列表需要搜索的速率相比,其速率微不足道,因此需要相对较慢初始化的算法很好。
我查看了Collections.binarySearch,但无法弄清楚它是如何使用的。我没有多少Java经验,所以如果有另一个可以类似于List使用的Collection,但更适合我需要的搜索类型,那就太棒了(我读过了)关于诸如地图和集合之类的文档,但没有认识到任何优势)。
答案 0 :(得分:2)
在维护排序列表的同时,您可以在&#39; X&#39;上使用二进制搜索。坐标以找到包含所需&#39; X&#39;的矩形的候选者,然后在&#39; Y&#39;上使用二进制搜索。坐标。
您应该自己实施二进制搜索,我无法看到您可以使用 Collections.binarySearch 方法的方法。
预期的复杂性:O(log n)为n的矩形数。 (它可能会有更多重复)
但是,为此,您应该在添加其他实例时对数组进行排序(在每次插入后排序)。
答案 1 :(得分:1)
使用HashSet。 Map
此处不合适,因为您未创建键值对,Stream
也不适合此上下文。
请务必覆盖equals()
中的hashCode()
和Rectangle
,如下所述:Why do I need to override the equals and hashCode methods in Java?
答案 2 :(得分:1)
您可以使用并行流这样搜索您的列表
public Rectangle findContainingRectangle(final int x, final int y) {
List<Rectangle> rectangles = new ArrayList<>();
Rectangle rec = rectangles.parallelStream().filter((r)->{
if(r.getX()==x && r.getY()==y){
return true;
}
return false;
}).findFirst().get();
return rec;
}
答案 3 :(得分:1)
只是多次运行二进制搜索 - 因为相同x的概率很低,因为你说它不会花费很多次所以它仍然会被登录
a)运行二进制搜索
b)如果找到则移除项目 - 并将索引保留在找到的位置
c)在a)用剩余的列表重复二进制搜索,直到返回null
d)然后你有一小部分索引,你可以看到哪一个是最小的
e)然后将删除的元素重新插入指定的位置
答案 4 :(得分:0)
您可以创建地图。
地图是关联两个值的最佳方式。您可以将“x”值与其列表中的第一个位置相关联。然后,您只需从列表中的第一个“x”位置循环到另一个“x”。
如果您在地图上找不到“x”,则列表上没有好的矩形。
通过这种方式,你不会探索所有糟糕的'x'条目。
答案 5 :(得分:0)
您可以尝试查看流的效果。我不确定它是否足够快但你可以测试它。
Rectangle rec = rects.stream().filter((r)->{
return r.contains(x, y);
}).findFirst().get();