在我的应用程序中,我需要检查2D坐标(x,y)的集合,以查看给定坐标是否在集合中,它需要尽可能快,并且只能从一个线程访问。 (这是用于碰撞检查)
有人可以帮我推动正确的方向吗?
答案 0 :(得分:5)
我能想到的绝对最快的是维持这些点的二维矩阵:
//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
矩阵即可。很明显,如果矩阵只创建一次,这种情况就会很快,并且可能会在将点添加到集合中时更新。
简而言之,基本的集合并不是完美的(尽管HashSet
会接近)。
修改强>
如果您找不到已经为您执行此操作的库,则可以很容易地将其调整为Set<Point>
。像这样:
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>...
}
答案 1 :(得分:2)
我会使用一些Trove collections数据结构。
如果您的积分存储为几个int
或几个float
,则可以将它们打包为long
:32位用于x-coord,32位用于y-坐标。然后,您可以使用TLongHashSet
优化HashSet
来处理原始数据(与普通的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
内打包浮动位。
答案 2 :(得分:1)
HashSet的。其O(1)平均值。如果你想要真正的O(1),你可以为你的对象创建一个包含对集合的引用。这样你就不能将 it 与你拥有的系列进行比较。
答案 3 :(得分:0)
与搜索相比,您多久更新一次这个集合?您应该根据它选择适当的数据结构。
Point2D实现可比,对吗?那么你最好的选择可能是TreeSet,它们速度非常快,我相信它们依赖于B +树,你可能知道它们在实际的数据库和文件系统中使用。
如果您认为您将对结构进行大量更新,请查看SkipList。它是guarentees O(log(操作))**注意这是针对您执行的所有操作,没有关于单个操作的运行时的保证)
答案 4 :(得分:-1)
您可以尝试某种排序集,例如treeset,因为您可以对其进行二进制搜索。