Поиск ближайшей пары точек на плоскости с неразличимыми координатами x за O(nlogn)

Большинство реализаций алгоритма поиска ближайшей пары точек на плоскости, которые я видел в Интернете, имеют один из двух недостатков: либо они не соответствуют времени выполнения O(nlogn), либо они не подходят для случая, когда некоторые точки имеют общую координату x. Является ли хеш-карта (или эквивалентная) обязательный оптимальной для решения этой проблемы?

Грубо говоря, рассматриваемый алгоритм (согласно CLRS Ch. 33.4):

  1. Для массива точек P создайте дополнительные массивы X и Y, чтобы X содержал все точки P, отсортированные по координате x, а Y содержал все точки P, отсортированные по координате y.
  2. Разделите точки пополам - проведите вертикальную линию, чтобы разделить X на два массива, XL и XR, и разделите Y аналогичным образом, чтобы YL содержал все точки слева от линии, а YR содержал все точки справа от линия, обе отсортированы по координате y.
  3. Сделайте рекурсивные вызовы для каждой половины, передав XL и YL одной и XR и YR другой, и найдите минимальное расстояние г в каждой из этих половин.
  4. Наконец, определите, есть ли пара с одной точкой слева и одной точкой справа от разделительной линии с расстоянием меньше г; с помощью геометрического аргумента мы обнаруживаем, что можем принять стратегию простого поиска в следующих 7 точках для каждой точки на расстоянии г от разделительной линии, что означает, что рекомбинация разделенных подзадач занимает всего O (n) шаг (даже если это выглядит n2 на первый взгляд).

Это имеет некоторые сложные граничные случаи. Один из способов справиться с этим — сортировать полосу точек на расстоянии г от разделительной линии на каждом этапе рекомбинации (например, здесь), но известно, что это приводит к решению O (nlog2n).

Другой способ, которым люди справляются с пограничными случаями, — это предположить, что каждая точка имеет отдельную координату x (например, здесь): обратите внимание на фрагмент в ближайшем Util, который добавляет к Pyl (или YL, как мы его называем), если координата x точки в Y <= линия или Pyr (YR) в противном случае. Обратите внимание: если все точки лежат на одной вертикальной линии, это приведет к тому, что мы запишем за конец массива в C++, поскольку мы записываем все точки н в YL.

Таким образом, сложный момент, когда точки могут иметь одну и ту же координату x, заключается в разделении точек в Y на YL и YR в зависимости от того, находится ли точка п в Y в XL или XR. Псевдокод в CLRS для этого (слегка отредактированный для краткости):

for i = 1 to Y.length
    if Y[i] in X_L
        Y_L.length = Y_L.length + 1;
        Y_L[Y_L.length] = Y[i]
    else Y_R.length = Y_R.length + 1;
        Y_R[Y_R.length] = Y[i]

Однако в отсутствие псевдокода, если мы работаем с простыми массивами, у нас нет волшебной функции, которая может определить, находится ли Y[i] в ​​X_L за время O(1). Если мы уверены, что все координаты x различны, конечно, мы знаем, что все, у кого координата x меньше разделительной линии, находится в XL, поэтому одним сравнением мы знаем, на какой массив разбить любую точку п в Y на . Но в случае, когда x-координаты не обязательно различны (например, в случае, когда все они лежат на одной вертикальной линии), нужна ли нам хеш-карта, чтобы определить, находится ли точка в Y в XL или XR, и успешно взломать вниз Y в YL и YR за время O(n)? Или есть другая стратегия?

достаточно просто повернуть все точки вокруг (0,0), чтобы гарантировать, что ни одна пара не имеет одинаковых X или одинаковых Y. Сам этот шаг должен занять NlogN времени. Не знаете, почему вы так против использования хэш-карты?

Bing Wang 07.05.2022 05:04

@BingWang не столько против этого, сколько просто интересно, не упустил ли я стратегию, в которой использовались более простые структуры данных - как я уже сказал, я не смог найти в Интернете решение, которое соответствовало бы моим двум критериям, что казалось странным, учитывая, насколько известен этот алгоритм. , поэтому я подумал, что могу упустить что-то простое.

jmath 07.05.2022 05:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
46
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Да, здесь работают как минимум два подхода.

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

Во-вторых, настроить алгоритм на G4G, чтобы использовать алгоритм разделения с линейным временем для разделения экземпляра и слияние с сортировкой с линейным временем для его захвата. Предположительно этого не было сделано, потому что автор ценил простоту сортировки относительно ранее упомянутых алгоритмов в большинстве языков программирования.

Убедившись, что я понимаю предложенную вами схему: в текущем алгоритме G4G они используют время O(1) для разделения входного массива P на левую и правую половины и время O(nlogn) на каждом шаге рекомбинации для сортировки полоса точек по координате y. Вместо этого вы предлагаете нам выполнить два случая работы O(n) — во-первых, используя время O(n) для разделения входных данных P на подмассивы, которые будут возвращаться из наших вызовов NearestUtils, отсортированных по координате y, чтобы мы могли затем объединить их вместе за время O(n) и использовать это как наш набор Y. Это правильно?

jmath 07.05.2022 16:02

@jmath, ты понял!

David Eisenstat 07.05.2022 16:48

Другие вопросы по теме