Эффективная структура данных для поиска редких данных

Ситуация:

Учитывая некоторые точки с координатой (x, y) Диапазон 0 < x < 100 000 000 и 0 < y < 100 000 000

Мне нужно найти наименьший квадрат, который содержит по крайней мере N точек точек на его краю и внутри него.

  • Я использовал вектор для хранения координат и поиска всех квадратов с длиной стороны minLength до длины стороны maxLength (применяя грубую силу в соответствующем пространстве)

    struct Point
    {
            int x;
            int y;
    };
    
    vector<Point> P;
    int minLength = sqrt(N) - 1;
    int maxLength = 0;
    
    //   bigx= largest x coordinate of any point
    //   bigy= largest y coordinate of any point
    //   smallx= smallest x coordinate of any point
    //   smally= smallest y coordinate of any point
    
    (bigx - smallx) < (bigy - smally) ? maxLength = (bigx - smallx) : maxLength = (bigy - smally);
    
  • Для каждого квадрата я поднял глаза, пройдя через полный вектор, чтобы увидеть, находится ли по крайней мере N точек на его краю и внутри него.

Это было довольно неэффективно.

Q1. Какую структуру данных следует использовать для повышения эффективности работы без изменения алгоритма, который я использовал?
Q2. Эффективный алгоритм для этой проблемы?

Ответ 1

Есть точки на 2 противоположных ребрах - если нет, вы можете сжать квадрат на 1 и по-прежнему содержать одинаковое количество точек. Это означает, что возможные координаты ребер ограничены возможными координатами точек входа. Однако входные точки, вероятно, не находятся на углах. (Для минимального прямоугольника были бы точки на всех 4 ребрах, так как вы можете сжать одно измерение без изменения другого)

Следующее, что нужно понять, это то, что каждая точка делит плоскость на 4 квадранта, и каждый квадрант содержит несколько точек. (Они могут содержать больше, чем общее количество точек, поскольку квадранты имеют одно перекрытие пикселей). Предположим, что NW (p) - количество точек на северо-запад от точки p, то есть тех, которые имеют x>=px and y>=py. Тогда число точек в квадрате NW(bottomleft) + NW(topright) - NW(bottomright) - NW(topleft).

Достаточно легко вычислить NW(p) для всех входных точек. Сортируйте их по x и равным x на y. Самая северо-западная точка имеет NW(p)==0. Следующий пункт может иметь NW(p)==1, если он находится к юго-востоку от первой точки, иначе он имеет NW(p)==0. Также полезно отслеживать SW (p) на этом этапе, поскольку вы работаете через точки с запада на восток, и поэтому они не сортируются с севера на юг. Вычислив NW(p), вы можете определить количество точек в квадрате S в O(1)

Напомним, что размер квадрата ограничен необходимостью иметь точки на противоположных ребрах. Предположим, что точки расположены слева (западный) и правый край - у вас все еще есть точки, отсортированные по порядку x. Начните с предположения, что левый край находится слева от координаты x, и посмотрите, что должен иметь правый край, содержащий N точек. Теперь сдвиньте левый край на следующую координату x и найдите новый правый край (и, следовательно, новый квадрат). Сделайте это, пока правый край квадрата не станет самой правой точкой.

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

Поскольку вы бегаете линейно через точки в направлениях x и y, эта часть является только O (N), а доминирующим фактором является сортировка O (N log N).

Ответ 2

Посмотрите http://en.wikipedia.org/wiki/Space_partitioning для алгоритмов, использующих технику Divide-and-Conquer для решения этой проблемы. Это определенно разрешимо в полиномиальное время.


Другие варианты алгоритмов могут быть в следующих строках.

  • Создайте vornoi-диаграмму для точек, чтобы получить информацию о соседях. [O (nlog (n))]
  • Теперь, используя Dynamic Programming, DP будет похож на проблему нахождения максимального подмассива в 2D-массиве. Здесь вместо суммы чисел вы будете следить за количеством очков перед этим.

    2.a По существу, будет рекурсия, подобная этой. [O (n)]

Число элементов в квадрате от (0,0) до (x, y) = (количество элемен- тов от квадрата (0,0 до ((x-1), y)) + (Количество элемен- тов в квадрате 0,0 - (x, y-1)) - (Число элементов в (0,0) - ((x-1), (y-1)))

Ваше повторение должно измениться для всех точек на его окрестности и влево и выше, а не только в точках выше и слева, как указано выше.

  • Как только DP готов, вы можете запросить точки в sqare в O (1). Другая петля O (n ^ 2), чтобы найти из всех возможных комбинаций и найти наименьший квадрат.

  • Вы можете даже жадно начинать с самых маленьких квадратов, так что вы можете закончить поиск, как только найдете подходящий квадрат.


Ответ 3

rtree позволяет осуществлять пространственный поиск, но не имеет реализации stl, хотя sqlite позволит привязывать. Это может ответить "получить все точки в радиусе действия", "k ближайших соседей"

Поиск области, которая имеет наиболее плотные данные, представляет собой проблему, похожую на кластеризацию.

Итерация по точкам и нахождение N ближайших записей в каждой точке. Тогда сгенерируйте наименьший центр окружности - Max (x) - min (x), Max (y) - min (y). Может быть сформирован квадрат, который содержит всех соседей, и будет находиться где-то между сторонами длины 2r и 2sqrt (r) по сравнению с кругом.

Время, затраченное на O (x), для построения структуры O (X N log (X)) для поиска наименьшего кластера

Ответ 4

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

Там, я думаю, ваш выбор с использованием вектора уже довольно хорош, потому что в целом векторы предлагают наилучшее соотношение полезной нагрузки/накладных расходов, а также самую быструю итерацию. Чтобы выяснить конкретные узкие места, используйте профилировщик, иначе вы только угадываете. С большими векторами есть несколько вещей, которые следует избегать:

  • Совокупность, это тратит пространство.
  • При распределении, это приводит к копированию, когда вектор выращен до необходимого размера.
  • Копирование.