4

我正在编写一种方法,该方法将点数组作为输入,并为数组中的每个点找到与其自身最近的点。我目前正在以蛮力的方式执行此操作(检查每个点与其他点)。我当前的实施没有对数组进行排序,但我可以使用 CompareByX 方法按 px 值对其进行排序。我正在检查算法的运行时间,如果 n 值很大,它会变得非常耗时。我对这个主题不是很了解,并且对不同类型的数据结构知之甚少,任何简单的帮助都会很棒!

我目前的代码是:

import java.util.*;
import java.lang.*;
import java.io.*;

class My2dPoint {
  double x;
  double y;

  public My2dPoint(double x1, double y1) {
    x=x1;
    y=y1;
  }

}


class CompareByX implements Comparator<My2dPoint> {
    public int compare(My2dPoint p1, My2dPoint p2) {
    if (p1.x < p2.x) return -1;
        if (p1.x == p2.x) return 0;
        return 1;
    }
}

    /* An object of the above comparator class is used by java.util.Arrays.sort() in main to sort an array of points by x-coordinates */

class Auxiliaries {

    public static double distSquared(My2dPoint p1, My2dPoint p2) {
        double result;
        result = (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y);
        return result;
    }

}

public class HW3 {
    public static void main (String argv []) throws IOException {
        int range = 1000000; // Range of x and y coordinates in points

        System.out.println("Enter the number of points");

        InputStreamReader reader1 = new InputStreamReader(System.in);
        BufferedReader buffer1 = new BufferedReader(reader1);
        String npoints = buffer1.readLine();
        int numpoints = Integer.parseInt(npoints);

        // numpoints is now the number of points we wish to generate

        My2dPoint inputpoints [] = new My2dPoint [numpoints];

        // array to hold points

        int closest [] = new int [numpoints];

        // array to record soln; closest[i] is index of point closest to i'th

        int px, py;
        double dx, dy, dist;
        int i,j;
        double currbest;
        int closestPointIndex;
        long tStart, tEnd;

        for (i = 0; i < numpoints; i++) {

          px = (int) ( range * Math.random());
          dx = (double) px;
          py = (int) (range * Math.random());
          dy = (double) py;
          inputpoints[i] = new My2dPoint(dx, dy);

        }

        // array inputpoints has now been filled



        tStart = System.currentTimeMillis();

        // find closest [0]


        closest[0] = 1;
        currbest = Auxiliaries.distSquared(inputpoints[0],inputpoints[1]);
        for (j = 2; j < numpoints; j++) {
           dist = Auxiliaries.distSquared(inputpoints[0],inputpoints[j]);
           if (dist < currbest) {
               closest[0] = j;
               currbest = dist;
           }
        }

        // now find closest[i] for every other i 

        for (i = 1; i < numpoints; i++) {
            closest[i] = 0;
            currbest = Auxiliaries.distSquared(inputpoints[i],inputpoints[0]);
            for (j = 1; j < i; j++) {
              dist = Auxiliaries.distSquared(inputpoints[i],inputpoints[j]);
              if (dist < currbest) {
               closest[i] = j;
               currbest = dist;
          }
            }

            for (j = i+1; j < numpoints; j++) {
              dist = Auxiliaries.distSquared(inputpoints[i],inputpoints[j]);
              if (dist < currbest) {
          closest[i] = j;
                  currbest = dist;
          }
            }
        }

        tEnd = System.currentTimeMillis();
        System.out.println("Time taken in Milliseconds: " + (tEnd - tStart));
    }
}
4

6 回答 6

2

我肯定会先按 x 排序。然后我会使用点之间的 x 距离作为快速拒绝测试:一旦你与一个邻居有距离,任何更近的邻居都必须在 x 中更近。这避免了对 x 范围之外的点的所有 distSquared 计算。每次你找到一个更近的邻居,你也收紧了你需要搜索的 x 的范围。

此外,如果 P2 是 P1 的最近邻居,那么我将使用 P1 作为 P2 最近邻居的初始猜测。

编辑:再三考虑,我会按范围最大的维度进行排序。

于 2011-03-02T22:18:20.607 回答
2

有一些相当标准的方法可以改进这种搜索,您想要获得的复杂程度取决于您搜索的点数。

一个相当常见的简单方法是按 X 或 Y 对点进行排序。然后,对于每个点,您可以在数组中向前和向后查找附近的点。记住你找到的最近的点有多远,当 X(或 Y)的差异大于你知道没有更近的点可以找到时。

您还可以使用树来划分空间。维基百科有一个页面提供了一些可能的算法。有时设置它们的成本大于您节省的成本。这就是您必须根据要搜索的点数来决定的事情。

于 2011-03-02T22:19:54.873 回答
2

最近邻搜索的蛮力只对少数点可行。

您可能希望一般地研究 kd-Trees 或空间数据结构。

这是 kd-Tree 的演示。 这就是维基百科所说的。

于 2011-03-02T22:17:26.440 回答
1

另一种比创建 kd 树更简单的可能性是使用邻域矩阵

首先将所有点放入二维方阵中。然后您可以运行完整或部分空间排序,因此点将在矩阵内变得有序。

Y 小的点可以移动到矩阵的顶行,同样,Y 大的点会移动到矩阵的底行。具有较小 X 坐标的点也会发生同样的情况,这些点应该移动到左侧的列。并且对称地,具有大 X 值的点将进入右列。

完成空间排序后(有很多方法可以通过串行或并行算法实现这一点),您可以通过访问点 P 实际存储在邻域矩阵中的相邻单元来查找给定点 P 的最近点。

您可以在以下论文中阅读有关此想法的更多详细信息(您可以在线找到它的 PDF 副本):基于紧急行为的 GPU 上的超大规模人群模拟

排序步骤为您提供了有趣的选择。您可以只使用论文中描述的奇偶转置排序,它实现起来非常简单(甚至可能在 CUDA 中)。如果你只运行一次,它会给你一个部分排序,如果你的矩阵是接近排序的,这可能已经很有用了。也就是说,如果您的点移动缓慢,它将为您节省大量计算。

如果你需要一个完整的排序,你可以多次运行这样的奇偶转置传递(如下面的维基百科页面所述):

http://en.wikipedia.org/wiki/Odd%E2%80%93even_sort

如果变化很小,一两次奇偶传球就足以使数组再次排序。

于 2014-02-08T23:00:55.877 回答
1

要么使用 kd-tree,要么使用好的库进行最近邻搜索。Weka包括一个。

于 2011-03-02T22:23:57.287 回答
0

如果您的点相对靠近,您可以按与某个点的距离排序(我认为它可以是任何点,但如果该点被视为起源)。

假设兴趣点是 A 点,距离 D。

从排序列表中的点 A 选择一些相对较小的 n 索引内的最近点(使用较大的 n 可能会提供更好的初始猜测,但会花费更长的时间)。如果该点与点 A 的线性距离为 g,则您知道最近的点与 A 的距离最多为 g。这样您只需考虑列表中距离 Dg 和 D+g 之间的点。

绘制图表可能有助于理解它。如果有人关心我会添加一个图表。

于 2019-02-19T00:00:17.373 回答