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

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

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

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

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

Дополнительные сведения:

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

Ответы

Ответ 1

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

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

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

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