Java - 在数组中搜索矩形(有效的方法)

时间:2016-01-18 22:28:41

标签: java arrays search

我有一个包含一个对象的数组,其中包含不同的变量(矩形,图像等等)

我正在寻找一种有效的方法来保存数组,并且是一种有效的搜索方式。

我每次需要搜索其矩形在渲染范围内的所有对象

有没有一种好的,有效的,快速的方法呢?

3 个答案:

答案 0 :(得分:2)

根据您修改“要渲染的内容”数组的频率与您尝试搜索内容的频率相比,您可能会以不同的方式查看数据。假设您只是偶尔修改数组,因此您有一些Renderable对象数组,其中每个Renderable都有一个返回矩形的getOutline():

Renderable[] arr = new Renderable[] { /* whatever */ };

加速频繁搜索的规范解决方案是根据搜索的属性对数组进行排序,然后使用O(log n)而不是O(n)的二进制搜索,就像遍历数组一样。在这种情况下,您不能这样做,因为您基本上是在2/4属性/键上编制索引:每个矩形的X范围和Y范围。

你可以做的是让四个数组由相同的对象组成(因为它们是引用,空间成本不大)并且每个数组都按相应的四个属性之一排序矩形:“顶部”(最小Y),“底部”(最大T),“左侧”(最小X)和“右侧”(最大X)。例如,您可以定义其中一个,如:

Comparator<Renderable> topComp = (r1, r2) -> r1.getOutline().top - r2.getOutline().top;
Renderable[] byTop = Arrays.stream(arr).sorted(topComp).toArray(Renderable[]::new);
// The same goes for byBottom, byLeft and byRight

中间的第一行使用lambda创建一个Comparator,该lambda对Renderable对象施加与其顶部坐标的自然顺序相同的排序。它可以被Comparator.comparingInt(r -> r.getOutline().top);替换,因为Comparator接口具有静态方法来创建这样做的比较对象。

现在,当你有一个要绘制的区域时,你可以使用二进制搜索来快速找到哪些矩形重叠:

// We'll say that the variable "reg" contains a rectangle that needs to be redrawn
// We'll make it a fake Renderable so "it" can be searched in the arrays
Renderable rReg = new FakeRenderable(reg);
int topPos    = Arrays.binarySearch(byTop,    rReg, topComp);
int bottomPos = Arrays.binarySearch(byBottom, rReg, bottomComp);
// etc for leftPos and rightPos

执行4 O(log n)查找后,每个xPos变量可能是正数或负数。

  • 如果为正(或零),则表示返回的索引是数组中与给定键相等的第一个对象的索引。索引将数组划分为“小于键”和“大于或等于键” - 如果你想在左侧留下“相等”的对象,只需搜索一个更大的键。
  • 如果是否定的,则没有对象与您的键完全相同,并且值为( - (插入点) - 1),其中插入点是第一个元素更大的索引,而不是键。因此,iFirstGreater = -(x + 1);其中x是binarySearch返回的值。然后,iFirstGreater将数组分区为“小于键”和“大于键”。

因此,在任何情况下,索引都会对四个数组进行分区。您有四个指向四个排序数组的索引,告诉您哪些可渲染对象在您的区域顶部上方/下方有一个“顶部”坐标,其上方/下方的“底部”低于/低于您所在区域的“底部”,左侧和右侧字段的相同位置相同。使用该信息,您可以决定每个可渲染对象是否为

  • 在绘图区域之外(并且应该忽略)
  • 在绘图区域内(并且应该完整绘制)
  • 重叠绘图区域(应该部分绘制/剪裁)

答案 1 :(得分:1)

for (Rectangle rectangle : array) {
     // check rectangle
}

答案 2 :(得分:0)

由于您要遍历数组中的所有元素,因此实际上没有任何内容。只需遍历所有元素并检查每个矩形:

for(int i = 0; i < myArray.length; i++) {
    Rectangle r = myArray[i].rectangle;
    //do something with r
}