Тонкая куча — различия между версиями
Genyaz (обсуждение | вклад) м |
Genyaz (обсуждение | вклад) м |
||
Строка 1: | Строка 1: | ||
[[Файл:Thin heap examples.png|200x200px|frame|Из [[Биномиальная куча#Биномиальное дерево|биномиального дерева]] ранга 3 получены два тонких дерева. Числа обозначают ранг вершин, черные вершины являются помеченными (не имеют самого левого сына).]] | [[Файл:Thin heap examples.png|200x200px|frame|Из [[Биномиальная куча#Биномиальное дерево|биномиального дерева]] ранга 3 получены два тонких дерева. Числа обозначают ранг вершин, черные вершины являются помеченными (не имеют самого левого сына).]] | ||
− | '''''Тонкая куча''''' {{---}} это структура данных, реализующая приоритетную очередь с теми же асимптотическими оценками, что и [[Фибоначчиева куча| | + | '''''Тонкая куча''''' {{---}} это структура данных, реализующая приоритетную очередь с теми же асимптотическими оценками, что и [[Фибоначчиева куча|фибоначчиева куча]], но имеющая большую практическую ценность из-за меньших констант. |
− | + | Тонкие кучи, как и многие другие [[Двоичная куча|кучеобразные]] структуры, аналогичны [[Биномиальная куча|биномиальным кучам]]. | |
= Тонкое дерево = | = Тонкое дерево = | ||
Строка 25: | Строка 25: | ||
|id=about_thin_tree | |id=about_thin_tree | ||
|statement=Тонкое дерево обладает следующими свойствами: | |statement=Тонкое дерево обладает следующими свойствами: | ||
− | # Для любого узла <tex>x</tex> либо <tex>Degree(x)=Rank(x)</tex>, в этом случае говорим, что узел <tex>x</tex> не помечен ( | + | # Для любого узла <tex>x</tex> либо <tex>Degree(x)=Rank(x)</tex>, в этом случае говорим, что узел <tex>x</tex> не помечен (полон); либо <tex>Degree(x)=Rank(x)-1</tex>, в этом случае говорим, что узел <tex>x</tex> помечен (не полон). |
− | # Корень не помечен ( | + | # Корень не помечен (полон). |
# Для любого узла <tex>x</tex> ранги его детей от самого правого к самому левому равны соответственно <tex>0,1,2,...,Degree(x)-1</tex>. | # Для любого узла <tex>x</tex> ранги его детей от самого правого к самому левому равны соответственно <tex>0,1,2,...,Degree(x)-1</tex>. | ||
# Узел <tex>x</tex> помечен тогда и только тогда, когда его ранг на 2 больше, чем ранг его самого левого сына, или его ранг равен 1, и он не имеет детей. | # Узел <tex>x</tex> помечен тогда и только тогда, когда его ранг на 2 больше, чем ранг его самого левого сына, или его ранг равен 1, и он не имеет детей. | ||
Строка 35: | Строка 35: | ||
{{Определение | {{Определение | ||
|id=thin_forest_def | |id=thin_forest_def | ||
− | |definition='''Тонкий лес''' (''thin forest'') {{---}} это набор | + | |definition='''Тонкий лес''' (''thin forest'') {{---}} это набор тонких деревьев, ранги которых не обязательно попарно различны. |
}} | }} | ||
Строка 41: | Строка 41: | ||
|id=about_thin_forest_with_n_nodes | |id=about_thin_forest_with_n_nodes | ||
|statement=Для любого натурального числа <tex>n</tex> существует тонкий лес, который содержит ровно <tex>n</tex> элементов и состоит из тонких деревьев попарно различных рангов. | |statement=Для любого натурального числа <tex>n</tex> существует тонкий лес, который содержит ровно <tex>n</tex> элементов и состоит из тонких деревьев попарно различных рангов. | ||
− | |proof=Действительно, любой [[Биномиальная куча#Биномиальное дерево|биномиальный]] | + | |proof=Действительно, любой [[Биномиальная куча#Биномиальное дерево|биномиальный лес]] является тонким, а для биномиального леса рассматриваемое утверждение справедливо. |
}} | }} | ||
{{Определение | {{Определение | ||
|id=thin_heap_def | |id=thin_heap_def | ||
− | |definition='''Тонкая куча''' (''thin heap'') {{---}} это [[Двоичная куча|кучеобразно]] нагруженный | + | |definition='''Тонкая куча''' (''thin heap'') {{---}} это [[Двоичная куча|кучеобразно]] нагруженный тонкий лес, то есть значение в любой вершине тонкого дерева не превосходит значений в её потомках. |
}} | }} | ||
Строка 55: | Строка 55: | ||
|about=О максимальном ранге узла | |about=О максимальном ранге узла | ||
|statement=В тонкой куче из <tex>n</tex> элементов <tex>D(n) \leqslant \log_{\Phi} n</tex>, где <tex dpi = "180">\Phi=\frac{1+\sqrt{5}}{2}</tex> {{---}} золотое сечение. | |statement=В тонкой куче из <tex>n</tex> элементов <tex>D(n) \leqslant \log_{\Phi} n</tex>, где <tex dpi = "180">\Phi=\frac{1+\sqrt{5}}{2}</tex> {{---}} золотое сечение. | ||
− | |proof=Сначала покажем, что узел ранга <tex>k</tex> в тонком дереве имеет не менее <tex>F_k \geqslant \Phi^{k-1}</tex> потомков, включая самого себя, где <tex>F_k</tex> — <tex>k</tex>-е число Фибоначчи | + | |proof=Сначала покажем, что узел ранга <tex>k</tex> в тонком дереве имеет не менее <tex>F_k \geqslant \Phi^{k-1}</tex> потомков, включая самого себя, где <tex>F_k</tex> — <tex>k</tex>-е число Фибоначчи. |
− | Действительно, пусть <tex>T_k</tex> {{---}} минимально возможное число узлов, включая самого себя, в тонком дереве ранга <tex>k</tex>. По свойствам <tex>1</tex> и <tex>3</tex> | + | Действительно, пусть <tex>T_k</tex> {{---}} минимально возможное число узлов, включая самого себя, в тонком дереве ранга <tex>k</tex>. По свойствам <tex>1</tex> и <tex>3</tex> тонкого дерева получаем следующие соотношения: |
<tex>T_0=1,T_1=1,T_k \geqslant 1+\sum_{i=0}^{k-2}T_i</tex> для <tex>k \geqslant 2</tex> | <tex>T_0=1,T_1=1,T_k \geqslant 1+\sum_{i=0}^{k-2}T_i</tex> для <tex>k \geqslant 2</tex> | ||
Строка 63: | Строка 63: | ||
Числа Фибоначчи удовлетворяют этому же рекуррентному соотношению, причем неравенство можно заменить равенством. Отсюда по индукции следует, что <tex>T_k \geqslant F_k</tex> для любых <tex>k</tex>. Неравенство <tex>F_k \geqslant \Phi^{k-1}</tex> [[Фибоначчиева куча#Лемма3|хорошо известно]]. | Числа Фибоначчи удовлетворяют этому же рекуррентному соотношению, причем неравенство можно заменить равенством. Отсюда по индукции следует, что <tex>T_k \geqslant F_k</tex> для любых <tex>k</tex>. Неравенство <tex>F_k \geqslant \Phi^{k-1}</tex> [[Фибоначчиева куча#Лемма3|хорошо известно]]. | ||
− | Теперь убедимся в том, что максимально возможный ранг <tex>D(n)</tex> | + | Теперь убедимся в том, что максимально возможный ранг <tex>D(n)</tex> тонкого дерева в тонкой куче, содержащей <tex>n</tex> элементов, не превосходит числа <tex>\log_{\Phi}(n)+1</tex>. |
Действительно, выберем в тонкой куче дерево максимального ранга. Пусть <tex>n^*</tex> {{---}} количество вершин в этом дереве, тогда <tex>n \geqslant n^* \geqslant \Phi^{D(n)-1}</tex>. | Действительно, выберем в тонкой куче дерево максимального ранга. Пусть <tex>n^*</tex> {{---}} количество вершин в этом дереве, тогда <tex>n \geqslant n^* \geqslant \Phi^{D(n)-1}</tex>. | ||
Строка 72: | Строка 72: | ||
== Представление тонкой кучи == | == Представление тонкой кучи == | ||
− | + | Тонкую кучу можно представить как [[Список#Односвязный список|односвязный список]] корней тонких деревьев, причем корень с минимальным ключом должен быть первым в списке. | |
− | Поскольку при работе с | + | Поскольку при работе с тонкой кучей ссылка на родителя требуется только у самого левого его ребенка, можно хранить ее вместо ссылки на левого брата этой вершины. |
− | Таким образом, для эффективной работы | + | Таким образом, для эффективной работы тонкой кучи необходимы следующие поля узла: |
*<tex>key</tex> {{---}} ключ (вес) элемента; | *<tex>key</tex> {{---}} ключ (вес) элемента; | ||
*<tex>child</tex> {{---}} указатель на самого левого ребенка узла; | *<tex>child</tex> {{---}} указатель на самого левого ребенка узла; | ||
Строка 83: | Строка 83: | ||
*<tex>rank</tex> {{---}} ранг узла (количество дочерних узлов данного узла). | *<tex>rank</tex> {{---}} ранг узла (количество дочерних узлов данного узла). | ||
− | Для ускорения проверки на | + | Для ускорения проверки на тонкость (''thinness'') можно отдельно хранить помеченность вершины. |
Также в вершине можно хранить любую дополнительную информацию. | Также в вершине можно хранить любую дополнительную информацию. | ||
− | Для работы с | + | Для работы с тонкой кучей достаточно иметь [[Список#Односвязный список|односвязный список]] ее корней. |
== Операции над тонкой кучей == | == Операции над тонкой кучей == | ||
− | Рассмотрим операции, которые можно производить над | + | Рассмотрим операции, которые можно производить над тонкой кучей. Время работы указано в таблице: |
{| border="1" | {| border="1" | ||
|-align="center" | |-align="center" | ||
Строка 115: | Строка 115: | ||
|} | |} | ||
− | Многие операции над | + | Многие операции над тонкой кучей выполняются так же, как и над [[Фибоначчиева куча|фиббоначиевой]]. |
Для [[Амортизационный анализ|амортизационного анализа]] операций применим [[Амортизационный анализ#Метод потенциалов|метод потенциалов]]. | Для [[Амортизационный анализ|амортизационного анализа]] операций применим [[Амортизационный анализ#Метод потенциалов|метод потенциалов]]. | ||
− | Пусть функция потенциала определена как <tex>\Phi = n + 2 \cdot m</tex> где <tex>n</tex> {{---}} это количество | + | Пусть функция потенциала определена как <tex>\Phi = n + 2 \cdot m</tex> где <tex>n</tex> {{---}} это количество тонких деревьев в куче, а <tex>m</tex> {{---}} это количество помеченных вершин. |
{{Утверждение | {{Утверждение | ||
Строка 125: | Строка 125: | ||
|statement=Определённый таким образом потенциал обладает свойствами: | |statement=Определённый таким образом потенциал обладает свойствами: | ||
# <tex>\Phi \geqslant 0</tex>. | # <tex>\Phi \geqslant 0</tex>. | ||
− | # Для пустой | + | # Для пустой тонкой кучи <tex>\Phi = 0</tex>. |
}} | }} | ||
Строка 166: | Строка 166: | ||
Пусть мы сделали <tex>ls</tex> связывающих шагов (''linking steps'') во время добавления в массив. | Пусть мы сделали <tex>ls</tex> связывающих шагов (''linking steps'') во время добавления в массив. | ||
− | Мы удалили корень из списка за <tex>O(1)</tex>, затем за <tex>O(D(n))</tex> нормализовали детей корня и добавили в корневой список, далее за <tex>O(D(n))+ | + | Мы удалили корень из списка за <tex>O(1)</tex>, затем за <tex>O(D(n))</tex> нормализовали детей корня и добавили в корневой список, далее за <tex>O(D(n))+ls</tex> получили новый корневой список, в котором за <tex>O(D(n))</tex> нашли минимальный корень и подвесили список за него. |
− | Получили фактическую стоимость <tex>O(D(n))+ | + | Получили фактическую стоимость <tex>O(D(n))+ls</tex>. С другой стороны, при добавлении детей в список мы увеличили потенциал <tex>\Phi</tex> не более чем на <tex>O(D(n))</tex>, а каждый связывающий шаг уменьшает наш потенциал <tex>\Phi</tex> на <tex>1</tex>. |
Cтоимость <tex>O(D(n))=O(\log(n))</tex>. | Cтоимость <tex>O(D(n))=O(\log(n))</tex>. |
Версия 14:22, 2 июня 2013
Тонкая куча — это структура данных, реализующая приоритетную очередь с теми же асимптотическими оценками, что и фибоначчиева куча, но имеющая большую практическую ценность из-за меньших констант.
Тонкие кучи, как и многие другие кучеобразные структуры, аналогичны биномиальным кучам.
Содержание
Тонкое дерево
Определение: |
Тонкое дерево (thin tree) биномиального дерева удалением у нескольких внутренних, то есть не являющихся корнем или листом, узлов самого левого сына. | ранга — это дерево, которое может быть получено из
Ограничение на принадлежность внутренним узлам вызвано тем, что у листьев детей нет, а если у корня удалить самого левого сына, то превратится в .
Утверждение: |
Ранг тонкого дерева равен количеству детей его корня. |
Для любого узла
в дереве обозначим:- — количество детей узла .
- биномиальном дереве . — ранг соответствующего узла в
Свойства тонкого дерева
Утверждение: |
Тонкое дерево обладает следующими свойствами:
|
Тонкая куча
Определение: |
Тонкий лес (thin forest) — это набор тонких деревьев, ранги которых не обязательно попарно различны. |
Утверждение: |
Для любого натурального числа существует тонкий лес, который содержит ровно элементов и состоит из тонких деревьев попарно различных рангов. |
Действительно, любой биномиальный лес является тонким, а для биномиального леса рассматриваемое утверждение справедливо. |
Определение: |
Тонкая куча (thin heap) — это кучеобразно нагруженный тонкий лес, то есть значение в любой вершине тонкого дерева не превосходит значений в её потомках. |
Пусть — максимально возможный ранг узла в тонкой куче, содержащей элементов.
Теорема (О максимальном ранге узла): |
В тонкой куче из элементов , где — золотое сечение. |
Доказательство: |
Сначала покажем, что узел ранга в тонком дереве имеет не менее потомков, включая самого себя, где — -е число Фибоначчи.Действительно, пусть — минимально возможное число узлов, включая самого себя, в тонком дереве ранга . По свойствам и тонкого дерева получаем следующие соотношения:для Числа Фибоначчи удовлетворяют этому же рекуррентному соотношению, причем неравенство можно заменить равенством. Отсюда по индукции следует, что хорошо известно. для любых . НеравенствоТеперь убедимся в том, что максимально возможный ранг тонкого дерева в тонкой куче, содержащей элементов, не превосходит числа .Действительно, выберем в тонкой куче дерево максимального ранга. Пусть Отсюда следует, что — количество вершин в этом дереве, тогда . . |
Представление тонкой кучи
Тонкую кучу можно представить как односвязный список корней тонких деревьев, причем корень с минимальным ключом должен быть первым в списке.
Поскольку при работе с тонкой кучей ссылка на родителя требуется только у самого левого его ребенка, можно хранить ее вместо ссылки на левого брата этой вершины.
Таким образом, для эффективной работы тонкой кучи необходимы следующие поля узла:
- — ключ (вес) элемента;
- — указатель на самого левого ребенка узла;
- — указатель на правого брата узла, либо на следующий корень, если текущий узел корень;
- — указатель на левого брата узла, либо на родителя, если текущий узел самый левый, либо null, если это корень;
- — ранг узла (количество дочерних узлов данного узла).
Для ускорения проверки на тонкость (thinness) можно отдельно хранить помеченность вершины. Также в вершине можно хранить любую дополнительную информацию.
Для работы с тонкой кучей достаточно иметь односвязный список ее корней.
Операции над тонкой кучей
Рассмотрим операции, которые можно производить над тонкой кучей. Время работы указано в таблице:
Многие операции над тонкой кучей выполняются так же, как и над фиббоначиевой.
Для амортизационного анализа операций применим метод потенциалов.
Пусть функция потенциала определена как
где — это количество тонких деревьев в куче, а — это количество помеченных вершин.Утверждение: |
Определённый таким образом потенциал обладает свойствами:
|
makeHeap
Для создания новой пустой тонкой кучи нужно вернуть ссылку на новый пустой корневой список, его потенциал
.Стоимость
.insert
Для вставки элемента в тонкую кучу нужно создать новое тонкое дерево из единственного узла с ключом
, добавить его в корневой список на первое место, если этот ключ минимален, иначе на второе. Потенциал увеличивается на 1.Стоимость
.getMin
Для обращения к минимальному элементу в тонкой куче нужно обратиться к первому корневому узлу списка и вернуть его ключ, потенциал
не меняется.Стоимость
.meld
Для объединения тонких куч нужно слить их корневые списки, ставя первым тот список, у которого ключ первого корня минимален. Суммарный потенциал
не меняется.Стоимость
.extractMin
Чтобы извлечь минимальный элемент из тонкой кучи нужно:
- Удалить корень с минимальным ключом из корневого списка.
- Уменьшить ранг для всех его помеченных детей.
- Cлить детей с корневым списком.
- Объединять, пока возможно, тонкие деревья одного ранга.
Это можно сделать, например, с помощью вспомогательного массива размером
, в -ой ячейке которого хранится корень тонкого дерева ранга .Изначально массив пуст, а мы добавляем в него все деревья нашего корневого списка.
При добавлении нового дерева мы, если дерево такого ранга уже есть в массиве, связываем его с существующим и пытаемся добавить новое дерево с рангом на
больше.Пусть мы сделали
связывающих шагов (linking steps) во время добавления в массив.Мы удалили корень из списка за
, затем за нормализовали детей корня и добавили в корневой список, далее за получили новый корневой список, в котором за нашли минимальный корень и подвесили список за него.Получили фактическую стоимость
. С другой стороны, при добавлении детей в список мы увеличили потенциал не более чем на , а каждый связывающий шаг уменьшает наш потенциал на .Cтоимость
.decreaseKey
После уменьшения ключа может быть нарушена кучеобразность, в этом случае мы переносим все поддерево с корнем в уменьшаемом элементе в корневой список, также обновляем минимум в тонкой куче.
Теперь могут быть нарушены свойства тонкого дерева, будем различать два вида нарушений:
- Братские нарушения — это нарушения третьего свойства тонкого дерева.
- Родительские нарушения — это нарушения первого или второго свойства тонкого дерева.
Назовем узел
узлом локализации братского нарушения среди детей узла , если ранг узла отличается от ранга его ближайшего правого брата на 2, либо он не имеет правого брата и его ранг равен 1.Назовем узел
узлом локализации родительского нарушения, если выполнено одно из трех условий:- Ранг узла на три больше, чем ранг его самого левого сына.
- Ранг узла равен двум, и он не имеет детей.
- Узел есть помеченный корень дерева.
Пусть узел
— это узел локализации братского нарушения.- Узел не помечен, тогда помещаем поддерево с корнем в самом левом сыне узла на место пропущенного в братском списке. Узел становится помеченным, дерево становится корректным, процедура исправления завершается.
- Узел помечен, тогда уменьшаем ранг узла на единицу. Теперь узлом локализации нарушения будет либо левый брат узла , либо его родитель, тогда нарушение станет родительским.
С помощью этих действий мы избавились от братских нарушений, теперь разберем родительские.
Пусть узел
— это узел локализации родительского нарушения, а узел — родитель узла .Переместим все поддерево с корнем в
в корневой список и уменьшим ранг .- Узел не был помечен, пометим его, тогда дерево станет корректным.
- Узел был помечен, тогда — новый узел локализации родительского нарушения, переходим к нему.
Продолжая эту процедуру, мы или остановимся, или дойдем до корня дерева, тогда достаточно сделать ранг корня на 1 больше ранга его самого левого сына.
Каждый промежуточный шаг рекурсии уменьшает количество помеченных узлов на 1 и добавляет не более одного дерева в корневой список, тогда на каждом промежуточном шаге потенциал уменьшается минимум на 1, отсюда амортизированная стоимость
.Стоимость
.delete
Чтобы удалить элемент из тонкой кучи нужно сначала выполнить
этого элемента до , а затем выполнить .Стоимость
.