Подходящий выбор структуры данных и алгоритма для быстрого поиска ближайшего соседа в 2D - PullRequest
14 голосов
/ 15 октября 2010

У меня есть набор данных приблизительно из 100 000 (X, Y) пар, представляющих точки в 2D-пространстве.Для каждой точки я хочу найти k-ближайших соседей.

Итак, мой вопрос - какая структура данных / алгоритм будет подходящим выбором, если я хочу полностью минимизироватьобщее время выполнения?

Я не ищу код - просто указатель на подходящий подход.Меня немного пугает диапазон вариантов, которые кажутся подходящими: квад-деревья, R-деревья, kd-деревья и т. Д.

Я думаю, что лучший подход - это построить структуру данных, тогдазапустить какой-либо поиск ближайшего соседа для каждой точки.Однако, поскольку (а) я знаю точки заранее, и (б) я знаю, что должен выполнить поиск каждой точки ровно один раз, возможно, есть лучший подход?

Некоторые дополнительные сведения:

  • Поскольку я хочу минимизировать все время выполнения, мне все равно, будет ли большая часть времени тратиться на поиск структуры.
  • Пары (X, Y) довольно хорошо распределенывне, поэтому мы можем предположить, что распределение почти равномерно.

1 Ответ

7 голосов
/ 15 октября 2010

Если k относительно мало (<20 или около того), и у вас приблизительно равномерное распределение, создайте сетку, которая перекрывает диапазон, в котором падают точки, выбранный таким образом, чтобы среднее число точек на сетку было удобно больше, чем k ( так что центрально расположенная точка обычно получает своих k соседей в этой одной точке сетки). Затем создайте набор других сеток, установленных наполовину от первого (перекрывающихся) вдоль каждой оси. Теперь для каждой точки вычислите, к какому элементу сетки она относится (поскольку сетки являются регулярными, поиск не требуется) и выберите одну из четырех (или сколь угодно много перекрывающихся сеток, которые у вас есть), у которой эта точка находится ближе всего к ее центру. </p>

Внутри каждого элемента сетки точки должны быть отсортированы по одной координате (скажем, х). Начиная с выбранного вами элемента (найдите его с помощью деления пополам), идите по отсортированному списку наружу, пока не найдете k элементов (опять же, если k мало, самый быстрый способ сохранить список из k лучших попаданий - использовать двоичную сортировку с вставкой). позволяя худшему совпадению падать с конца при вставке; сортировка вставок обычно превосходит все остальное (до 30 элементов на современном оборудовании). Продолжайте движение до тех пор, пока ваш самый дальний ближайший сосед не окажется ближе к вам, чем ближайшие точки от вас по оси x (т.е. не считая их смещения по оси y, поэтому не может быть новой точки, которая могла бы быть ближе, чем найденная до сих пор k-я) .

Если у вас еще нет k точек или у вас есть k точек, но одна или несколько стен элемента сетки находятся ближе к вашей точке интереса, чем самая дальняя из k точек, добавьте соответствующие соседние элементы сетки в поиск .

Это должно дать вам производительность примерно как O(N*k^2), с относительно низким постоянным коэффициентом. Если k велико, то эта стратегия слишком упрощена, и вы должны выбрать алгоритм, который является линейным или логарифмическим по k, как могут быть kd-деревья.

...