在我的应用程序中,我需要检查 2D 坐标 (x,y) 的集合以查看给定坐标是否在集合中,它需要尽可能快,并且只能从一个线程访问。(用于碰撞检查)
有人可以推动我朝着正确的方向前进吗?
在我的应用程序中,我需要检查 2D 坐标 (x,y) 的集合以查看给定坐标是否在集合中,它需要尽可能快,并且只能从一个线程访问。(用于碰撞检查)
有人可以推动我朝着正确的方向前进吗?
我能想到的绝对最快的方法是维护这些点的二维矩阵:
//just once
int[][] occurrences = new int[X_MAX][Y_MAX];
for (Point p : points ) {
occurrences[p.x][p.y]++;
}
//sometime later
if ( occurrences[x][y] != 0 ) {
//contains Point(x, y)
}
如果您不在乎有多少,那么只需一个boolean
矩阵即可。显然,如果矩阵只创建一次,并且可能会随着点添加到集合中而更新,这只会很快。
简而言之,基本的 Collections 并不完美(尽管 aHashSet
会接近)。
编辑
Set<Point>
如果您还没有找到可以为您执行此操作的库,则可以轻松地将其改编为 a 。像这样的东西:
public class PointSet implements Set<Point> {
private final boolean[][] data;
public PointSet(int xSize, int ySize) {
data = new boolean[xSize][ySize];
}
@Override
public boolean add(Point e) {
boolean hadIt = data[e.x][e.y];
data[e.x][e.y] = true;
return hadIt;
}
@Override
public boolean contains(Object o) {
Point p = (Point) o;
return data[p.x][p.y];
}
//...other methods of Set<Point>...
}
我会使用一些Trove 集合数据结构。
如果您的点存储为一对int
或一对,float
您可以将它们打包成一个long
:x 坐标为 32 位,y 坐标为 32 位。然后,您可以使用为处理原始数据TLongHashSet
而HashSet
优化的 a(与普通 java 集合相比,它会更快并且消耗更少的内存)。
如果您有int
坐标,它将类似于
static private long computeKey(int h1, int h2)
{
return ((long)h1) << 32 | h2;
}
计算密钥然后使用它
TLongHashSet set = new TLongHashSet()
set.add(long v);
set.addAll(long[] v);
set.containsAll(..);
如果你有float
值,你可以做同样的事情,但你必须在long
.
哈希集。它的 O(1) 平均值。如果你想要真正的 O(1),你可以为你的对象创建一个包装器,它引用了一个集合。这样一来,您就不能将其与您拥有的收藏进行比较。
与搜索相比,您需要多久更新一次集合?您应该基于此选择适当的数据结构。
Point2D 实现了可比性,对吧?那么你最好的选择可能是 TreeSet,它们非常快,而且我相信它们依赖于 B+ 树,你可能知道它在实际的数据库和文件系统中使用。
如果您认为您将对结构进行大量更新,请查看 SkipList。它保证 O(log(operations)) **注意这是针对您所做的所有操作,没有关于单个操作的运行时间的保证)
您可以尝试某种排序集,例如树集,因为您可以对其进行二进制搜索。