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またはYで並べ替えることです。次に、各ポイントについて、配列内で前方と後方の両方に移動して、近くのポイントを探します。あなたが見つけた最も近いものがどれだけ離れているかを覚えておいてください、そしてX(またはY)の差がそれよりも大きいとき、あなたが見つけるために残っているより近い点がないことを知っています。

ツリーを使用してスペースを分割することもできます。ウィキペディアには、いくつかの可能なアルゴリズムを提供するページがあります。それらを設定するためのコストは、節約したものよりも大きい場合があります。これは、検索しているポイントの数に基づいて決定する必要がある種類のことです。

于 2011-03-02T22:19:54.873 に答える
2

最近傍探索のブルート フォースは、少数の点に対してのみ実行可能です。

一般に、kd-Trees または空間データ構造を調べたいと思うかもしれません。

これは kd-Tree のデモです。 これはウィキペディアが言っていることです。

于 2011-03-02T22:17:26.440 に答える
2

私は間違いなく最初に x でソートします。次に、ポイント間のx距離を簡単な拒否テストとして使用します.1つの隣人までの距離を取得したら、より近い隣人はxでより近くなければなりません. これにより、x 範囲外の点に対するすべての distSquared 計算が回避されます。より近い近傍を見つけるたびに、検索する必要がある x の範囲も狭まります。

また、P2 が P1 の最近傍である場合、P1 を P2 の最近傍の初期推定として使用します。

編集:考え直して、範囲が最大の次元で並べ替えます。

于 2011-03-02T22:18:20.607 に答える
1

kd ツリーを使用するか、最近傍検索に優れたライブラリを使用してください。Wekaには1つ含まれています。

于 2011-03-02T22:23:57.287 に答える
1

kd ツリーを作成するよりも簡単なもう 1 つの可能性は、近傍行列を使用することです。

まず、すべてのポイントを 2D 正方行列に配置します。次に、完全または部分的な空間ソートを実行して、ポイントがマトリックス内で順序付けられるようにします。

Y が小さい点は行列の一番上の行に移動し、同様に、Y が大きい点は一番下の行に移動します。X 座標が小さい点でも同じことが起こり、左側の列に移動する必要があります。そして対称的に、大きな X 値を持つポイントは右側の列に移動します。

空間的な並べ替えを行った後 (シリアルまたはパラレル アルゴリズムの両方で、これを達成する方法はたくさんあります)、点 P が実際に近傍行列に格納されている隣接セルにアクセスするだけで、特定の点 P の最も近い点を検索できます。

このアイデアの詳細については、次の論文 (PDF コピーをオンラインで見つけることができます) で読むことができます: Supermassive Crowd Simulation on GPU based on Emergent Behavior

並べ替えの手順により、興味深い選択肢が得られます。この論文で説明されている偶奇転置ソートだけを使用できます。これは実装が非常に簡単です (おそらく CUDA でも)。このパスを 1 回だけ実行すると、部分的な並べ替えが行われます。これは、マトリックスがほぼ並べ替えられている場合にすでに役立ちます。つまり、ポイントの動きが遅い場合は、多くの計算を節約できます。

完全な並べ替えが必要な場合は、そのような偶奇転置パスを数回実行できます (次の Wikipedia ページで説明されています)。

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

変更が小さい場合は、1 つまたは 2 つの偶奇パスで、配列を再度並べ替えることができます。

于 2014-02-08T23:00:55.877 に答える