Изменения

Перейти к: навигация, поиск

Квадродеревья

1497 байт добавлено, 00:28, 7 января 2014
Нет описания правки
<div style="background-color: #ABCDEF; font-size: 16px; font-weight: bold; color: #000000; text-align: center; padding: 4px; border-style: solid; border-width: 1px;">Эта статья находится в разработке!</div><includeonly>[[Категория: В разработке]]</includeonly>{{ptready}}
== Определение и построение ==
'''Квадродерево''' {{---}} дерево, каждая внутренняя вершина которого содержит 4 ребёнка. Любому узлу квадродерева соответствует некоторый квадрат. Если внутренней вершине <tex>v</tex> соответствует какой-то квадрат <tex>a</tex>, то её детям соответствуют четверти квадрата <tex>a</tex> (см. картинку).
Пусть дано множество точек <tex>P</tex>, для которого нужно построить квадродерево. Начнём с некоторого квадрата <tex>\sigma</tex>, содержащего все точки из <tex>P</tex>. Если он не дан явно, его можно легко найти за линейное время от числа вершин. Пусть <tex>\sigma = [x_0, x_1] \times [y_0, y_1]</tex>. Обозначим <tex>x_m = (x_0 + x_1) / 2; y_m = (y_0 + y_1) / 2</tex>. Тогда:
* если <tex>P</tex> содержит не больше одной точки, то квадродерево состоит из одного листа, которому соответствует квадрат <tex>\sigma</tex>;
* иначе корнем дерева делаем вершину <tex>v</tex>, которой соответствует квадрат <tex>\sigma</tex>, а его её дети {{---}} <tex>v_{NE}, v_{NW}, v_{SW}, v_{SE}</tex>, и им соответствуют квадраты <tex>\sigma_{NE} = (x_m, x_1] \times (y_m, y_1]</tex>, <tex>\sigma_{NW} = [x_0, x_m] \times (y_m, y_1]</tex>, <tex>\sigma_{SW} = [x_0, x_m] \times [y_0, y_m]</tex>, <tex>\sigma_{SE} = (x_m, x_1] \times [y_0, y_m]</tex>. Затем таким же образом рекурсивно превращаем каждого ребёнка в квадродерево для множества точек, лежащих в соответствующем квадратесоответствующих четвертях.
== Леммы и теоремы ==
Сторона квадрата на глубине <tex>i</tex>, очевидно, равна <tex>s / 2^i</tex>. Максимальное расстояние между двумя точками внутри квадрата достигается, когда они являются вершинами диагонали, то есть на глубине <tex>i</tex> расстояние между любыми двумя точками в одном квадрате не превосходит <tex>s \sqrt 2 / 2^i</tex>. Поскольку внутренняя вершина квадродерева содержит хотя бы 2 точки в соответствующем ей квадрате, то <tex>s \sqrt 2 / 2^i \geq c</tex>, так как <tex>c</tex> {{---}} минимальное расстояние между точками в <tex>P</tex>. Отсюда следует, что <tex>i \leq log(s \sqrt 2 / c) = log (s / c) + 1/2</tex>. Значит, глубина любой внутренней вершины не превосходит <tex>log (s / c) + 1/2</tex>, из чего следует утверждение леммы.
}}
Также можно заметить, что в идеальном случае дерево будет полностью сбалансировано (то есть размеры всех детей каждой внутренней вершины одинаковы), и тогда глубина составит порядка логарифма от числа вершин.
Размер дерева и время построения будут также зависеть и от <tex>n</tex> {{---}} мощности <tex>P</tex>.
</code>
[https://groups.google.com/forum/#!topic/uw.cs.cs240/MGfrsvKAiMA Тут] говорят, что работает за <tex>\theta Theta (d + n)</tex>. ВидимоНу а вообще, можно делать по-тупому (без квадродерева, просто храня точки в списке или векторе) за <tex>O(n)</tex>, так и естьтупо проверяя все точки, но я пока не понял, как это обосноватьвидимо, может показатьсятак на практике быстрее получается. Не очень понятно, используются ли вообще обычные квадродеревья кем-либо для этой цели. Насчёт времени работы: понятно, что если какая-то вершина, попадающая в ответ, находится на дне дерева, то будет работать минимум за глубину. При этом в ответе могут быть примерно все точки, поэтому будет работать минимум за <tex>\Theta(n)</tex>. Отсюда <tex>\Theta (d + n)</tex>. Поскольку вершин в дереве <tex>O(d \theta cdot n)</tex>, то очевидно, что будет работать не дольше, чем <tex>O(d \cdot n)</tex>.Ну а вообщеНо, можно делать судя по-тупому за всему, <tex>O(d + n)</tex>тоже верная оценка. Собственно, ноосталось доказать, видимочто <tex>O(d + n)</tex> на запрос, так обычно быстрее получаетсяи конспект готов.
''Видимо, в этом месте заканчивается всё то, что относится к данному билету, далее идут просто полезные факты (сбалансированное упомянуто просто так, а сжатое нужно для первого билета)''
== Сжатое квадродерево ==
Обычное квадродерево может иметь слишком большую глубину независимо от количества точек. Сжатое дерево лишено данного недостатка, имеет имея глубину <tex>O(n)</tex>, и на его основе строится [[Skip quadtree: определение, время работы | Skip Quadtree]].
{{Определение
|id=interesting
|definition=
Назовём квадрат '''интересным''', если соответствующая ему вершина дерева имеет хотя бы 2 непустых ребёнка (то есть таких, что в их квадратах содержится хотя бы одна точка) или является корнем. Понятно, что любой квадрат <tex>p</tex>, содержащий хотя бы две точки, содержит единственный наибольший интересный квадрат.
}}
[[Файл:Compressed Quadtree.png | 500px | thumb | Пример сжатого квадродерева (справа сжатая версия левого)]]
Понятно, что любой квадрат <tex>p</tex>, содержащий хотя бы две точки, содержит единственный наибольший интересный квадрат. Сжатое квадродерево получается сжатием обычного таким образом, чтобы остались только интересные квадраты. Неинтересные квадраты расщепляются, и их пустые Пустые дети неинтересных квадратов удаляются. Для каждого интересного квадрата <tex>p</tex> будем хранить 4 указателя для каждой четверти этого квадрата. Если четверть содержит две или более точки, то указатель ссылается на наибольший интересный квадрат в этой четверти. Если четверть содержит одну точку, то указатель ссылается на эту точку. Наконец, если четверть не содержит точек, то указатель сделаем нулевым. Картинка проясняет ситуацию. Квадратикам соответствуют интересные квадраты, красным кружкам {{---}} точки, белым кружкам {{---}} пустота.
== О размерах сжатого квадродерева ==
Сжатое квадродерево для <tex>n</tex> точек имеет <tex>O(n)</tex> вершин и глубину <tex>O(n)</tex>.
|proof=
Как отмечалось в представленной выше теореме, достаточно доказать оценку <tex>O(n)</tex> для числа внутренних вершин, каждая из которых является интересным квадратом (Кэп: то есть для числа интересных квадратов это надо доказать). Докажем по индукции, что в квадродереве для <tex>n</tex> точек количество интересных квадратов меньше либо равно <tex>n</tex>:
* для <tex>n = 1</tex> это очевидно;
* пусть в квадродереве <tex>n > 1</tex> точек. Рассмотрим корень, у него обязательно должно быть хотя бы 2 непустых ребёнка. Если хотя бы один из детей является точкой, то остальные непустые дети являются деревьями, в которых суммарно меньше не больше <tex>n - 1</tex> точек(и в каждом их меньше <tex>n</tex>). Значит, в них суммарно меньше не больше <tex>n - 1</tex> интересных квадратов (по индукционному предположению). Следовательно, во всём квадродереве меньше не больше <tex>n</tex> интересных квадратов. Если же все непустые дети корня являются интересными квадратами, то мы всё ранво равно можем применить индукционное предположение ко всем детям и получить то же самое, поскольку во всех поддеревьях будет меньше <tex>n</tex> точек (ибо их суммарно <tex>n</tex> и везде есть хотя бы одна, так как дети непустые).Таким образом, квадродерево для <tex>n</tex> точек имеет <tex>O(n)</tex> вершин. Глубина, очевидно, тоже <tex>O(n)</tex>, поскольку на каждом уровне есть хотя бы одна вершина (Кэп). При этом лучшей оценки получше нет (то есть глубина <tex>\thetaTheta(n)</tex>). На картинке в правом дереве можно на место левого нижнего красного кружка поставить опять такое дерево и так делать сколь угодно долго, получим высоту глубину <tex>\thetaTheta(n)</tex>.
}}
== Операции над сжатым квадродеревом ==
Все операции похожи на аналогичные в обычных деревьях поиска. Только они делаются за <tex>O(n)</tex>. Того же самого можно добиться тупым перебором, храня точки просто в списке или векторе. Хотя на практике, наверно, так побыстрее. Но всё же сама по себе структура не особо полезна, зато пополезнее будет [[Skip quadtree: определение, время работы | Skip Quadtree]].
=== Поиск ===
Нам дают точку, хотим найти наименьший интересный квадрат, который её содержит. Довольно очевидно, как это делать: просто идём вниз по дереву в нужную четверть, начиная с корня. В какой-то момент закончим, найдя наименьший интересный квадрат, который содержит искомую точку. Дальше легко проверить, есть ли такая точка в квадродереве. Работает, очевидно, за высоту, которая линейно зависит от числа точек (см. выше).
=== Вставка ===
Сначала запускаем поиск, находим наименьший квадрат, в который надо вставиться, понимаем, в какую четверть вставляться. Если она пустая, то всё совсем просто, меняем 1 указатель. Если там что-то естьточка, то добавим новый интересный квадрат, поправим <tex>O(1)</tex> указателей, и всё хорошо. Опять же Таким образом, нужно сделать поиск за <tex>O(n)</tex> и ещё <tex>O(потому что поиск столько длится1)</tex> действий.
=== Удаление ===
Начнём, разумеется, с поиска. Если такая точка есть, то обнулим поинтер на неё, при этом квадрат, который был интересный, может больше не быть интересным. При этом родитель этого квадрата всё равно останется интересным. Значит, в таком случае просто заменим этот квадрат на точку. В общем, тут тоже <tex>O(n)</tex> из-за поиска и <tex>O(потому что поиск столько длится1)</tex> на само удаление.
== Литература ==
* ''van Kreveld, de Berg, Overmars, Cheong {{---}} Computational Geometry. Algorithms and Applications.'' Страница 309. Тут можно почитать про квадродеревья.
170
правок

Навигация