根据您修改“要呈现的事物”数组的频率与您尝试在其中搜索事物的频率相比,您可能会从查看数据的不同方式中受益。假设您只是偶尔修改数组,因此您有一些 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 变量可能是正数或负数。
- 如果为正数(或零),则表示返回的索引是数组中与给定键等于的第一个对象的索引。索引将数组划分为“小于键”和“大于或等于键” - 如果您想将“相等”对象留在左侧,只需搜索比键大一的键。
- 如果为负数,则没有对象与您的键完全相等,值为 (-(insertion point) - 1),其中插入点是第一个元素的索引大于钥匙。因此,
iFirstGreater = -(x + 1); 其中 x 是 binarySearch 返回的值。然后,iFirstGreater 将数组划分为“小于键”和“大于键”。
因此,在任何情况下,索引都会划分四个数组。您有四个索引到四个排序数组中,告诉您哪些可渲染对象在区域顶部上方/下方具有“顶部”坐标,在区域顶部上方/下方具有“底部”坐标,左右字段相同。使用该信息,您可以决定每个可渲染对象是否是
- 绘图区域之外(应该忽略)
- 绘图区域内(且应完整绘制)
- 重叠绘图区域(应部分绘制/裁剪)