【问题标题】:Java - Search rectangle in an array(efficient way to do so)Java - 在数组中搜索矩形(有效的方法)
【发布时间】:2016-01-18 22:28:40
【问题描述】:

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

我正在寻找一种保存数组的有效方法,以及一种搜索它的有效方法。

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

有没有好的、高效、快速的方法?

【问题讨论】:

  • 是接口数组吗?还是只是一个对象的数组?
  • 我强烈建议您添加更多详细信息。数组中有哪些不同的对象。它们的相对大小或结构是什么?你想把它保存在哪里?文件还是数据库?
  • @jacob ArrayList ,tile 是我创建的一个类,其中包含有关 tile 的所有内容(矩形、精灵等)。
  • @MithunS ,我有一个 ArrayList,tile 是我创建的一个类,其中包含有关 tile 的所有内容(矩形、精灵等)。我正在寻找一种方法来有效地搜索数组以找到其矩形位置在一定范围内的图块

标签: java arrays search


【解决方案1】:

根据您修改“要呈现的事物”数组的频率与您尝试在其中搜索事物的频率相比,您可能会从查看数据的不同方式中受益。假设您只是偶尔修改数组,因此您有一些 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 -&gt; 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 将数组划分为“小于键”和“大于键”。

因此,在任何情况下,索引都会划分四个数组。您有四个索引到四个排序数组中,告诉您哪些可渲染对象在区域顶部上方/下方具有“顶部”坐标,在区域顶部上方/下方具有“底部”坐标,左右字段相同。使用该信息,您可以决定每个可渲染对象是否是

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

【讨论】:

  • 非常感谢 :) 对我帮助很大!
【解决方案2】:
for (Rectangle rectangle : array) {
     // check rectangle
}

【讨论】:

  • 向阅读器扔代码并不是很有用。请确定问题中的核心问题、已采取哪些措施来解决问题以及原因。
  • 请看我写的,我正在寻找一种快速有效的方法。那是做到这一点的基本方法,它并不是真正有效且相当缓慢。还是谢谢
【解决方案3】:

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

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

【讨论】:

  • 请看我写的,我正在寻找一种快速有效的方法。那是做到这一点的基本方法,它并不是真正有效且相当缓慢。还是谢谢
  • @PazHaviv 如果您必须在一些对象之间进行选择而离开其他对象,并且必须找到一种方法来知道如何搜索以找到您想要的对象,那将是另一回事。据我所知,您想检查每个对象,所以除了检查每个对象之外别无他法。
  • 我想检查哪些矩形在玩家视图的范围内。我标记了 Javier Martin 给我的答案,这是一个非常有效的答案
  • 是的,但您不知道列表中的所有对象是否实际上都是矩形。你的问题是这样说的。这就是为什么每个人都说,您需要通过列表首先确定对象是否是矩形。上面答案的假设并不完全正确,如果对象不是矩形怎么办?那你会怎么处理呢?
  • @MithunS 据我了解,有一个对象数组,它们都有一个矩形(除其他外)作为属性,他想以最快的方式检查所有矩形。跨度>
猜你喜欢
  • 2021-10-08
  • 2020-03-20
  • 1970-01-01
  • 2018-10-21
  • 2011-08-25
  • 2016-08-14
  • 1970-01-01
  • 1970-01-01
  • 2011-06-06
相关资源
最近更新 更多