Большинство реализаций алгоритма поиска ближайшей пары точек на плоскости, которые я видел в Интернете, имеют один из двух недостатков: либо они не соответствуют времени выполнения O(nlogn), либо они не подходят для случая, когда некоторые точки имеют общую координату x. Является ли хеш-карта (или эквивалентная) обязательный оптимальной для решения этой проблемы?
Грубо говоря, рассматриваемый алгоритм (согласно CLRS Ch. 33.4):
Это имеет некоторые сложные граничные случаи. Один из способов справиться с этим — сортировать полосу точек на расстоянии г от разделительной линии на каждом этапе рекомбинации (например, здесь), но известно, что это приводит к решению 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)? Или есть другая стратегия?
@BingWang не столько против этого, сколько просто интересно, не упустил ли я стратегию, в которой использовались более простые структуры данных - как я уже сказал, я не смог найти в Интернете решение, которое соответствовало бы моим двум критериям, что казалось странным, учитывая, насколько известен этот алгоритм. , поэтому я подумал, что могу упустить что-то простое.
Да, здесь работают как минимум два подхода.
Во-первых, как предлагает Бинг Ван, нужно применить вращение. Если угол достаточно мал, это равносильно разрыву связей по координате y после сравнения по x, никакой другой математики не требуется.
Во-вторых, настроить алгоритм на G4G, чтобы использовать алгоритм разделения с линейным временем для разделения экземпляра и слияние с сортировкой с линейным временем для его захвата. Предположительно этого не было сделано, потому что автор ценил простоту сортировки относительно ранее упомянутых алгоритмов в большинстве языков программирования.
Убедившись, что я понимаю предложенную вами схему: в текущем алгоритме G4G они используют время O(1) для разделения входного массива P на левую и правую половины и время O(nlogn) на каждом шаге рекомбинации для сортировки полоса точек по координате y. Вместо этого вы предлагаете нам выполнить два случая работы O(n) — во-первых, используя время O(n) для разделения входных данных P на подмассивы, которые будут возвращаться из наших вызовов NearestUtils, отсортированных по координате y, чтобы мы могли затем объединить их вместе за время O(n) и использовать это как наш набор Y. Это правильно?
@jmath, ты понял!
достаточно просто повернуть все точки вокруг (0,0), чтобы гарантировать, что ни одна пара не имеет одинаковых X или одинаковых Y. Сам этот шаг должен занять NlogN времени. Не знаете, почему вы так против использования хэш-карты?