给定三维空间中的大量点(x,y,z坐标),需要找到原点的十个最近点。 任何已经可用的java标准库的指针。 还要感谢您对使用最佳数据结构和排序算法以经济高效的方式实现解决方案的意见,同时兼顾时间和空间? 提前谢谢。
答案 0 :(得分:0)
为每个值计算sqrt(x ^ 2 + y ^ 2 + z ^ 2)并进行排序。在这里,我已经缓存了结果,以提高效率。
// generate
Set<Point3D> points = new HashSet<Point3D>();
for (int i = 0; i < 20; i++) {
points.add(new Point3D(-5d + 10d * Math.random(), -5d + 10d
* Math.random(), -5d + 10d * Math.random()));
}
// distances
final Map<Point3D, Double> distanceCache = new IdentityHashMap<Point3D, Double>();
for (Point3D point : points) {
distanceCache.put(
point,
Math.sqrt(point.getX() * point.getX() + point.getY()
* point.getY() + point.getZ() * point.getZ()));
}
// sort
List<Point3D> tmp = new ArrayList<Point3D>(points);
Collections.sort(tmp, new Comparator<Point3D>() {
@Override
public int compare(Point3D o1, Point3D o2) {
return Double.compare(distanceCache.get(o2),
distanceCache.get(o1));
}
});
// print results
System.out.println(tmp.subList(0, 10));
for (Point3D point : tmp.subList(0, 10)) {
System.out.printf("%.2f,", distanceCache.get(point));
}
假设某种3D点类
private static class Point3D {
private double x;
private double y;
private double z;
public Point3D(double x, double y, double z) {
super();
this.x = x;
this.y = y;
this.z = z;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
@Override
public String toString() {
return new Formatter().format("%.2f,%.2f,%.2f", x, y, z).toString();
}
}
答案 1 :(得分:0)
Adam已经提供了一个良好而强大的通用解决方案。但是,在您的特定情况下,您可以使用一些可能的优化。然而,它确实在很大程度上取决于您定义的大型点集。如果我们谈论数千点,那么请继续阅读。
首先,在处理欧几里德距离时,重要的是要记住比较平方距离将给出与实际距离之间的比较相同的顺序。因此,您不必执行相对昂贵的平方根操作。只需直接比较x*x+y*y+z*z
即可。
其次,最好的通用排序算法在O(n * log n)
时间内工作。这适用于例如合并排序,堆排序和快速排序。但是,如果您有大量的点并且您只想找到 k第一个点,其中 k 很小,那么选择不同的算法有时是可行的。特别是一旦您只找到这些元素就可以中止排序。例如,即使进行线性O(n)搜索以找到每个元素并执行 k 次也会产生O(k * n)的复杂度。如果 k 小于 log n ,那么此方法将更有效。请注意,这只是一个简单的selection sort。 Heap sort也可能是找到 k 第一个元素的合理选择。
您还应该考虑是否要构建一次点集,然后多次运行算法,只需在每次运行之间添加/删除/移动几个点,然后维护剩余的数据结构可能更有效有序,然后从中取出第一个 k 元素。这可能就像在平方距离上排序的TreeSet
一样简单。或者,值得保持octree或其他3D空间分区数据结构中的点。这样你就可以只查看八叉树中最接近原点的节点。