Ортогональный поиск — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Сбалансированное дерево поиска)
(Сбалансированное дерево поиска)
Строка 30: Строка 30:
 
Каждая из функций <tex>range{\_}search(y_{min}, y_{max})</tex> будет работать в худшем случае за <tex>O(\log n)</tex>, отсюда получаем итоговое время выполнения запроса <tex>O(\log^2 n)</tex>. Что касается памяти, то в сбалансированном дереве поиска <tex>O(\log n)</tex> слоев, а каждый слой содержит массивы, содержащие в сумме ровно <tex>n</tex> точек, соответственно вся структура в целом занимает <tex>O(n\log n)</tex> памяти.
 
Каждая из функций <tex>range{\_}search(y_{min}, y_{max})</tex> будет работать в худшем случае за <tex>O(\log n)</tex>, отсюда получаем итоговое время выполнения запроса <tex>O(\log^2 n)</tex>. Что касается памяти, то в сбалансированном дереве поиска <tex>O(\log n)</tex> слоев, а каждый слой содержит массивы, содержащие в сумме ровно <tex>n</tex> точек, соответственно вся структура в целом занимает <tex>O(n\log n)</tex> памяти.
  
Такую структуру данных можно при необходимости обобщить на случай большей размерности.
+
Такую структуру данных можно при необходимости обобщить на случай большей размерности. Пусть у нас есть множество точек из <tex>n</tex>-мерного пространства, каждая из которых представляется как <tex>n</tex> координатных чисел: <tex>(\xi_1, \xi_2, ... , \xi_n)</tex>. Тогда, строя дерево поиска по координате <tex>\xi_i</tex>, в каждой вершине будем хранить другое дерево поиска с ключом <tex>\xi_{i+1}</tex>, составленное из точек, лежащих в соответствующем поддереве. В дереве поиска, составленном по предпоследней координате <tex>\xi_{n-1}</tex>, уже не будет необходимости хранить в каждой вершине целое дерево, поскольку при переходе на последнюю координату <tex>\xi_{n}</tex> дальнейший поиск производиться не будет, поэтому в вершинах будем хранить массивы, так же, как и в двумерном случае. Оценим занимаемую память и время запроса: при добавлении следующей координаты асимптотика обеих величин умножается на  <tex>\log n</tex>. Отсюда, получаем оценку <tex>O(\log^{n} n)</tex> на время запроса и <tex>O(n\log^{n-1} n)</tex> на занимаемую память.
 +
 
 +
Такой же результат можно получить с помощью [[Сжатое многомерное дерево отрезков|сжатого многомерного дерева отрезков]].
  
 
== Квадро дерево ==
 
== Квадро дерево ==
  
 
== Инкрементальное квадро дерево ==
 
== Инкрементальное квадро дерево ==

Версия 17:11, 19 мая 2012

Простейший случай

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

Line with dots and segment.png

Данная задача решается с помощью функций из STL - upper_bound и lower_bound.

upper_bound возвращает наименьшее значение больше данного, lower_bound - наибольшее значение меньше данного.

Рассмотрим на примере:

Upper bound and lower bound.png

Код реализации:

template<class RauIter, class OutIter, class Scalar> OutIter range_search(RauIter p, RauIter q, OutIter out)
{
   return std::copy(lower_bound(p, q, l), upper_bound(p, q, r), out);
}

Сбалансированное дерево поиска

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

Для этого возьмем любое сбалансированное дерево поиска и наполним его точками [math](x, y)[/math] из множества. В качестве ключа будет использоваться [math]x[/math]-координата точки. Теперь модернизируем дерево: в каждой вершине дерева будем хранить отсортированный по [math]y[/math]-координате массив точек, которые содержатся в соответствующем поддереве. В такой структуре данных поиск точек в заданном прямоугольнике [math](x_{min}, x_{max}) \times (y_{min}, y_{max})[/math] будет выглядеть следующим образом:

  1. Выберем из дерева поиска те точки, [math]x[/math]-координата которых лежит в интервале [math](x_{min}, x_{max})[/math]. Сделаем это точно так же, как делается запрос сверху в дереве отрезков. Из аналогии с деревом отрезков следует, что мы ответ мы получим в виде [math]O(\log n)[/math] поддеревьев дерева поиска.
  2. Для каждого из полученных поддеревьев обратимся к массиву содержащихся в нем точек и запустим от него приведенную выше функцию [math]range{\_}search(y_{min}, y_{max})[/math]. Все полученные таким образом точки и будут составлять ответ.

Каждая из функций [math]range{\_}search(y_{min}, y_{max})[/math] будет работать в худшем случае за [math]O(\log n)[/math], отсюда получаем итоговое время выполнения запроса [math]O(\log^2 n)[/math]. Что касается памяти, то в сбалансированном дереве поиска [math]O(\log n)[/math] слоев, а каждый слой содержит массивы, содержащие в сумме ровно [math]n[/math] точек, соответственно вся структура в целом занимает [math]O(n\log n)[/math] памяти.

Такую структуру данных можно при необходимости обобщить на случай большей размерности. Пусть у нас есть множество точек из [math]n[/math]-мерного пространства, каждая из которых представляется как [math]n[/math] координатных чисел: [math](\xi_1, \xi_2, ... , \xi_n)[/math]. Тогда, строя дерево поиска по координате [math]\xi_i[/math], в каждой вершине будем хранить другое дерево поиска с ключом [math]\xi_{i+1}[/math], составленное из точек, лежащих в соответствующем поддереве. В дереве поиска, составленном по предпоследней координате [math]\xi_{n-1}[/math], уже не будет необходимости хранить в каждой вершине целое дерево, поскольку при переходе на последнюю координату [math]\xi_{n}[/math] дальнейший поиск производиться не будет, поэтому в вершинах будем хранить массивы, так же, как и в двумерном случае. Оценим занимаемую память и время запроса: при добавлении следующей координаты асимптотика обеих величин умножается на [math]\log n[/math]. Отсюда, получаем оценку [math]O(\log^{n} n)[/math] на время запроса и [math]O(n\log^{n-1} n)[/math] на занимаемую память.

Такой же результат можно получить с помощью сжатого многомерного дерева отрезков.

Квадро дерево

Инкрементальное квадро дерево