检查矩形列表中单击哪个矩形的最快方法

时间:2018-07-25 01:07:39

标签: java sorting search

我有一个具有x,y,宽度和高度的矩形对象。我有这些在屏幕上显示的矩形的列表。保证它们没有重叠。给定用户的单击位置(x和y坐标),我想查看这些矩形中的哪个被单击了(由于它们不重叠,因此最多可以单击一个矩形)。

很明显,我可以查看所有这些内容,并检查是否单击了用户,但是这很慢,因为屏幕上有很多内容。当我在列表中插入新矩形时,可以使用某种比较方法来使矩形保持排序。是否有某种方法可以使用类似于二进制搜索的方法,以减少找到单击哪个矩形所需的时间?

注意:矩形可以是任何大小。 谢谢:)

编辑:要了解我在做什么,请访问koalastothemax.com

3 个答案:

答案 0 :(得分:1)

这在很大程度上取决于您的应用程序和详细信息,我们尚不了解最佳解决方案是什么。但是,据我所知,我想说的是,您可以制作一个指向矩形的2D数组。该2D阵列将直接映射到屏幕上的像素。因此,如果将数组设置为10x20,则坐标x除以屏幕宽度乘以10(投射到int)将成为第一个索引,而y除以屏幕高度乘以20将成为您的y索引。使用x和y索引,您可以直接映射到它所指向的矩形。如果索引布局不正确,有些索引可能为空,有些索引可能指向多个矩形,但这对我来说似乎是最简单的方法,而无需对应用程序了解太多。

答案 1 :(得分:0)

我想出的最快方法绝对不是最有效的内存。这通过利用摊销哈希表具有恒定查找时间这一事实而起作用。它将映射矩形所具有的每个点。仅当您使用整数时,这才真正有效。如果您使用四舍五入,则可以使它与浮点数一起使用。

确保Point类具有哈希码和equals函数。

public class PointCheck
{
    public Map<Point, Rect> pointMap;

    public PointCheck()
    {
        pointMap = new HashMap<>();
    }

    /**
     *  Map all points that contain the rectangle
     * to the rectangle.
     */
    public void addRect(Rect rect)
    {
        for(int i = rect.x; i < rect.x + rect.width; ++i)
        {
            for(int j = rect.y; j < rect.y + rect.height; ++i)
            {
                pointMap.put(new Point(i, j), rect);
            }
        }
    }

    /**
     *  Returns the rectangle clicked, null
     * if there is no rectangle.
     */
    public Rect checkClick(Point click)
    {
        return pointMap.get(click);
    }
}

编辑: 只是想我应该提一下:哈希表值中保存的所有矩形都是对原始矩形的引用,不是克隆。

答案 2 :(得分:0)

过去,在开发模拟时,我已经解决了一个非常相似的问题。在我的情况下,坐标是双精度的(因此不可能进行整数索引),并且可能有数亿个坐标需要搜索。

我的解决方案是创建一个Axis类,以将每个轴表示为一系列范围。保证范围从最小到最大,并且班级足够聪明,可以在添加新范围时将自身拆分为多个部分。每个范围都存储了一个通用对象。该课程使用二进制搜索来快速找到范围。

因此,该类大致如下:

class Axis<T> {
    public Axis(double min, double max, Supplier<T> creator);
    public Stream<T> add(double from, double to);
    public T get(double coord);
}

add方法需要返回流,因为添加的范围可能涵盖多个范围。

要存储矩形:

Axis<Axis<Rectangle>> rectanges = new Axis<>(0.0, 100.0, 
    () -> new Axis<>(0.0, 100.0, Rectangle::new));

rectangles.add(x, x + w).forEach(r -> r.add(y, y + h).forEach(Rectangle::setPresent));

并找到一个矩形:

rectangles.get(x).get(y);

请注意,始终会存储一个对象,因此您需要使用诸如Rectangle.NULL之类的表示形式来表示“不存在”。或者,您可以将其设置为Optional<Rectangle>(尽管这种间接操作会占用大量内存并处​​理大量矩形)。

我只是在这里提供了高级设计,而不是任何实现细节,因此,如果您需要更多有关如何使其工作的信息,请告诉我。在范围划分上正确掌握逻辑并非易事。但是我可以保证,即使有大量矩形,它也非常快。