Алгоритм поиска точек, которые находятся дальше друг от друга - лучше, чем O (n ^ 2) - PullRequest
14 голосов
/ 29 июня 2011

В моей программе у меня есть набор точек.В целях перемасштабирования я ищу два наиболее удаленных узла, а затем вычисляю множитель, на который нужно умножить все координаты, чтобы максимальное расстояние было равно некоторому предопределенному, который я определяю.Я использую, чтобы найти две самые отдаленные точки, однако, проблематично для больших наборов точек, поскольку это O(n^2);псевдокод (расстояния, которые уже были рассчитаны, пропускаются):

 for each point in points:
     for each other point in points:
         if distance between point and other point > max
             max = distance between point and other point

Есть ли что-то быстрее?

Ответы [ 8 ]

18 голосов
/ 29 июня 2011

Если вам нужен только масштаб, а не точные точки, вы можете сделать это за O (n) время с некоторой погрешностью.Подумайте о простом случае изготовления ограничительной рамки.Вычислите минимальное значение x из всех точек, максимальное значение x, минимальное значение y и максимальное значение y.Эти четыре числа дают вам максимальную ограничивающую рамку вокруг ваших точек с максимальной ошибкой 1 - (1 / sqrt (2)) около 30%.Вы можете уменьшить это, добавив больше сторон к вашему квадрату.Подумайте о случае восьмиугольника.Чтобы вычислить минимальное и максимальное значения для других сторон, вы должны повернуть свою систему координат.

Ошибка и время выполнения разбиваются следующим образом.

shape - время выполнения - максимальная ошибка

  • квадрат - 2N - 30%
  • восьмиугольник - 4N - 16%
  • 16 сторон - 8N - 4%
  • 32 стороны - 16N - 1%

Вот уравнение для максимальной ошибки, с которой я столкнулся.

angle = 180 / sides
max_error = (1 / cos angle) - cos angle

Дайте мне знать, если мне нужно добавить диаграмму, объясняющую это.

16 голосов
/ 30 июня 2011

Следующее может помочь поставить алгоритмы линейного времени среднего случая (для диаметра конечного множества) в более ясном свете, а также контрастировать проблемы многомерной и плоской геометрии.

В 1983Мегиддо дал детерминированный алгоритм линейного времени для наименьшего вмещающего круга (или сферы в более высоких измерениях).

В общем случае вмещающий круг будет иметь две или три точки на своей границе, итаким образом, нахождение двух наиболее удаленных друг от друга может быть выполнено «в среднем» за постоянное время, когда известен ограничивающий круг.В более высоких измерениях число точек общего положения, необходимых на границе сферы, увеличивается (D + 1 балл для измерения D), и действительно стоимость вычисления расстояния между одной парой точек возрастает линейно с измерением.

Подмножество точек, лежащих на ограничивающем круге или сфере, также находится за линейное время.В теоретическом наихудшем случае все точки будут лежать на ограничивающей окружности или сфере, но это, по крайней мере, более строго, чем просто наличие всех точек на выпуклой оболочке.Если точки на сфере независимо возмущены, скажем, вдоль радиальных линий, то общее положение гарантируется с вероятностью 1, и приблизительный диаметр можно найти только из точек D + 1 на пересмотренной вмещающей сфере.Это рандомизированное приближение имеет квадратичную зависимость от размерности, но имеет только линейную сложность по количеству точек.

Если точки, лежащие на ограничивающем круге, «отсортированы» (циклически, конечно), можно найти самую дальнюю парув линейном времени, полагаясь на «унимодальность» круга (это означает, что расстояния от фиксированной точки монотонно растут до антипода, а затем падают) , чтобы амортизировать стоимость вычисления расстояний .К сожалению, такая сортировка привела бы к шагу с O (n log n) временной сложностью, и это оказалось оптимальным в худшем случае для точных детерминированных методов в плоском случае.

В 2001 году Рамосу удалось показать O (n log n) детерминированный алгоритм для трехмерных наборов , но метод настолько сложен, что реализация может быть непрактичной или медленнойчем поиск всех пар методом перебора до очень больших наборов данных .

Для более высоких измерений многие авторы рассмотрели рандомизированные или приближенные алгоритмы.См. тезис Петра Индика (2000) для приближенных методов только с полиномиальной зависимостью от размерности для различных задач близости.

13 голосов
/ 29 июня 2011

Как уже упоминалось в в этом ответе , вы ищете «диаметр» набора из N точек, хорошо известную проблему в вычислительной геометрии.Есть в основном два шага:

  1. Найти выпуклую оболочку из точек. Существуют алгоритмы , которые являются O (N ln N), наихудший случай.На практике QuickHull обычно является быстрым выбором, хотя потенциально O (N ^ 2) наихудший случай.Реализацию QHull удобно вызывать из командной строки.Библиотека CGAL обеспечивает реализацию C ++

  2. Антиподальные пары на выпуклой оболочке являются кандидатами на самые дальние точки.Можно искать точки антиподов с помощью алгоритма, подобного Вращающиеся штангенциркули за O (N) время.

Задача может быть обобщена на задачу "всех дальних пар": для каждой точки i найдите самую дальнюю точку j-Мы сейчас ищем N пар очков.В решении снова используется выпуклая оболочка, но теперь вторую часть можно выполнить с помощью алгоритма матричного поиска .

4 голосов
/ 29 июня 2011

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

Таким образом, вам не нужно проверять, является ли определенный дом в Нью-Йорке самым дальним от Парижа,Вы уже определили, что Австралия еще дальше

3 голосов
/ 29 июня 2011

См. Прекрасный ответ Джона Феминеллы на этот похожий вопрос. Вы должны получить O (n log n) для среднего случая.

3 голосов
/ 29 июня 2011

Расстояние от A до B совпадает с расстоянием от B до A. Вы можете легко изменить алгоритм, чтобы таким образом исключить половину вычислений. Это все равно будет O(n^2), но будет вдвое быстрее.

То есть вместо вычисления всех недиагональных элементов матрицы расстояний P x P:

P = {A, B, C, D, ...}

  + A + B + C + D + ...
A |   | * | * | * | ...
B | * |   | * | * | ...
C | * | * |   | * | ...
D | * | * | * |   | ...
  |   |   |   |   |

Вы можете вычислить либо верхний треугольник:

  + A + B + C + D + ...
A |   | * | * | * | ...
B |   |   | * | * | ...
C |   |   |   | * | ...
D |   |   |   |   | ...
  |   |   |   |   |

или нижний треугольник:

  + A + B + C + D + ...
A |   |   |   |   | ...
B | * |   |   |   | ...
C | * | * |   |   | ...
D | * | * | * |   | ...
  |   |   |   |   |
1 голос
/ 29 июня 2011

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

Каждая точка может хранить самую дальнюю точку от нее и перепроверять каждое добавление точки, если новая точка находится дальше.

Когда вы запрашиваете, вы просто просматриваете все точки и смотрите на их кешированные точки.

Вы получите O (n) для ввода новой точки и O (n) для самого дальнего запроса.

1 голос
/ 29 июня 2011

Я не уверен, что если поместить точки в пространственный индекс и запросить его, то получится алгоритм O (n log n).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...