Тонкая куча — различия между версиями
Genyaz (обсуждение | вклад) (Изображение тонких деревьев) |
Genyaz (обсуждение | вклад) (Добавлены ссылки) |
||
Строка 1: | Строка 1: | ||
− | [[Файл:Thin heap examples.png|200x200px|frame|Из биномиального дерева ранга 3 получены два тонких дерева. Числа обозначают ранг вершин, черные вершины являются помеченными (не имеют самого левого сына).]] | + | [[Файл:Thin heap examples.png|200x200px|frame|Из [[Биномиальная куча#Биномиальное дерево|биномиального дерева]] ранга 3 получены два тонких дерева. Числа обозначают ранг вершин, черные вершины являются помеченными (не имеют самого левого сына).]] |
− | '''''Тонкая куча''''' {{---}} это структура данных, реализующая приоритетную очередь с теми же асимптотическими оценками, что и '' | + | '''''Тонкая куча''''' {{---}} это структура данных, реализующая приоритетную очередь с теми же асимптотическими оценками, что и [[Фибоначчиева куча|''фибоначчиева куча'']], но имеющая большую практическую ценность из-за меньших констант. |
− | ''Тонкие кучи'', как и многие другие кучеобразные структуры, аналогичны ''биномиальным кучам''. | + | ''Тонкие кучи'', как и многие другие [[Двоичная куча|кучеобразные]] структуры, аналогичны [[Биномиальная куча|''биномиальным кучам'']]. |
= Тонкое дерево = | = Тонкое дерево = | ||
{{Определение | {{Определение | ||
|id=thin_tree_def. | |id=thin_tree_def. | ||
− | |definition='''Тонкое дерево''' (''thin tree'') <tex>T_k</tex> ранга <tex>k</tex> {{---}} это дерево, которое может быть получено из биномиального дерева <tex>B_k</tex> удалением у нескольких внутренних, то есть не являющихся корнем или листом, узлов самого левого сына. | + | |definition='''Тонкое дерево''' (''thin tree'') <tex>T_k</tex> ранга <tex>k</tex> {{---}} это дерево, которое может быть получено из [[Биномиальная куча#Биномиальное дерево|биномиального дерева]] <tex>B_k</tex> удалением у нескольких внутренних, то есть не являющихся корнем или листом, узлов самого левого сына. |
}} | }} | ||
Строка 19: | Строка 19: | ||
Для любого узла <tex>x</tex> в дереве <tex>T_k</tex> обозначим: | Для любого узла <tex>x</tex> в дереве <tex>T_k</tex> обозначим: | ||
* <tex>Degree(x)</tex> {{---}} количество детей узла <tex>x</tex>. | * <tex>Degree(x)</tex> {{---}} количество детей узла <tex>x</tex>. | ||
− | * <tex>Rank(x)</tex> {{---}} ранг соответствующего узла в биномиальном дереве <tex>B_k</tex>. | + | * <tex>Rank(x)</tex> {{---}} ранг соответствующего узла в [[Биномиальная куча#Биномиальное дерево|биномиальном дереве]] <tex>B_k</tex>. |
== Свойства тонкого дерева == | == Свойства тонкого дерева == | ||
Строка 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'') {{---}} это [[Двоичная куча|кучеобразно]] нагруженный ''тонкий лес''. |
}} | }} | ||
Строка 70: | Строка 70: | ||
== Представление тонкой кучи == | == Представление тонкой кучи == | ||
− | ''Тонкую кучу'' можно представить как односвязный список корней ''тонких деревьев'', причем корень с минимальным ключом должен быть первым в списке. | + | ''Тонкую кучу'' можно представить как [[Список#Односвязный список|односвязный список]] корней ''тонких деревьев'', причем корень с минимальным ключом должен быть первым в списке. |
Поскольку при работе с ''тонкой кучей'' ссылка на родителя требуется только у самого левого его ребенка, можно хранить ее вместо ссылки на левого брата этой вершины. | Поскольку при работе с ''тонкой кучей'' ссылка на родителя требуется только у самого левого его ребенка, можно хранить ее вместо ссылки на левого брата этой вершины. | ||
Строка 84: | Строка 84: | ||
Также в вершине можно хранить любую дополнительную информацию. | Также в вершине можно хранить любую дополнительную информацию. | ||
− | Для работы с ''тонкой кучей'' достаточно иметь | + | Для работы с ''тонкой кучей'' достаточно иметь [[Список#Односвязный список|односвязный список]] ее корней. |
== Операции над тонкой кучей == | == Операции над тонкой кучей == | ||
Строка 113: | Строка 113: | ||
|} | |} | ||
− | Многие операции над ''тонкой кучей'' выполняются так же, как и над ''фиббоначиевой''. | + | Многие операции над ''тонкой кучей'' выполняются так же, как и над [[Фибоначчиева куча|''фиббоначиевой'']]. |
− | Для амортизационного анализа применим метод потенциалов. | + | Для [[Амортизационный анализ|амортизационного анализа]] операций применим [[Амортизационный анализ#Метод потенциалов|метод потенциалов]]. |
Пусть функция потенциала определена как <tex>\Phi = n + 2 \cdot m</tex> где <tex>n</tex> {{---}} это количество ''тонких деревьев'' в куче, а <tex>m</tex> {{---}} это количество помеченных вершин. | Пусть функция потенциала определена как <tex>\Phi = n + 2 \cdot m</tex> где <tex>n</tex> {{---}} это количество ''тонких деревьев'' в куче, а <tex>m</tex> {{---}} это количество помеченных вершин. | ||
Строка 125: | Строка 125: | ||
# Для пустой ''тонкой кучи'' <tex>\Phi = 0</tex>. | # Для пустой ''тонкой кучи'' <tex>\Phi = 0</tex>. | ||
}} | }} | ||
− | |||
=== makeHeap === | === makeHeap === | ||
− | + | Для создания новой пустой тонкой кучи нужно вернуть ссылку на новый пустой корневой список, его потенциал <tex>\Phi=0</tex>. | |
− | |||
Стоимость <tex>O(1)</tex>. | Стоимость <tex>O(1)</tex>. | ||
Строка 135: | Строка 133: | ||
=== insert === | === insert === | ||
− | + | Для вставки элемента в тонкую кучу нужно создать новое тонкое дерево из единственного узла с ключом <tex>x</tex>, добавить его в корневой список на первое место, если этот ключ минимален, иначе на второе. Потенциал <tex>\Phi</tex> увеличивается на 1. | |
Стоимость <tex>O(1)</tex>. | Стоимость <tex>O(1)</tex>. | ||
Строка 141: | Строка 139: | ||
=== getMin === | === getMin === | ||
− | + | Для обращения к минимальному элементу в тонкой куче нужно обратиться к первому корневому узлу списка и вернуть его ключ, потенциал <tex>\Phi</tex> не меняется. | |
Стоимость <tex>O(1)</tex>. | Стоимость <tex>O(1)</tex>. | ||
Строка 147: | Строка 145: | ||
=== meld === | === meld === | ||
− | + | Для объединения тонких куч нужно слить их корневые списки, ставя первым тот список, у которого ключ первого корня минимален. Суммарный потенциал <tex>\Phi</tex> не меняется. | |
Стоимость <tex>O(1)</tex>. | Стоимость <tex>O(1)</tex>. | ||
=== extractMin === | === extractMin === | ||
+ | Чтобы извлечь минимальный элемент из тонкой кучи нужно: | ||
+ | # Удалить корень с минимальным ключом из корневого списка. | ||
+ | # Уменьшить ранг для всех его помеченных детей. | ||
+ | # Cлить детей с корневым списком. | ||
+ | # Объединять, пока возможно, тонкие деревья одного ранга. | ||
− | |||
− | |||
− | |||
− | |||
Это можно сделать, например, с помощью вспомогательного массива размером <tex>O(D(n))</tex>, в <tex>i</tex>-ой ячейке которого хранится корень тонкого дерева <tex>T_i</tex> ранга <tex>i</tex>. | Это можно сделать, например, с помощью вспомогательного массива размером <tex>O(D(n))</tex>, в <tex>i</tex>-ой ячейке которого хранится корень тонкого дерева <tex>T_i</tex> ранга <tex>i</tex>. | ||
Строка 172: | Строка 171: | ||
=== decreaseKey === | === decreaseKey === | ||
+ | Чтобы уменьшить ключ элемента нужно: | ||
Стоимость <tex>O(1)</tex>. | Стоимость <tex>O(1)</tex>. | ||
=== delete === | === delete === | ||
− | + | Чтобы удалить элемент из тонкой кучи нужно сначала выполнить <tex>decreaseKey</tex> этого элемента до <tex>-\infty</tex>, а затем выполнить <tex>extractMin</tex>. | |
Стоимость <tex>O(\log(n))</tex>. | Стоимость <tex>O(\log(n))</tex>. |
Версия 08:00, 26 мая 2013
Тонкая куча — это структура данных, реализующая приоритетную очередь с теми же асимптотическими оценками, что и фибоначчиева куча, но имеющая большую практическую ценность из-за меньших констант.
Тонкие кучи, как и многие другие кучеобразные структуры, аналогичны биномиальным кучам.
Содержание
Тонкое дерево
Определение: |
Тонкое дерево (thin tree) биномиального дерева удалением у нескольких внутренних, то есть не являющихся корнем или листом, узлов самого левого сына. | ранга — это дерево, которое может быть получено из
Ограничение на принадлежность внутренним узлам вызвано тем, что у листьев детей нет, а если у корня удалить самого левого сына, то превратится в .
Утверждение: |
Ранг тонкого дерева равен количеству детей его корня. |
Для любого узла
в дереве обозначим:- — количество детей узла .
- биномиальном дереве . — ранг соответствующего узла в
Свойства тонкого дерева
Утверждение: |
Тонкое дерево обладает следующими свойствами:
|
Тонкая куча
Определение: |
Тонкий лес (thin forest) — это набор тонких деревьев, ранги которых не обязательно попарно различны. |
Утверждение: |
Для любого натурального числа существует тонкий лес, который содержит ровно элементов и состоит из тонких деревьев попарно различных рангов. |
Действительно, любой биномиальный лес является тонким, а для биномиального леса рассматриваемое утверждение справедливо. |
Определение: |
Тонкая куча (thin heap) — это кучеобразно нагруженный тонкий лес. |
Пусть — максимально возможный ранг узла в тонкой куче, содержащей элементов.
Теорема (О максимальном ранге узла): |
В тонкой куче из элементов , где — золотое сечение. |
Доказательство: |
Сначала покажем, что узел ранга в тонком дереве имеет не менее потомков, включая самого себя, где — -е число Фибоначчи, определяемое соотношениями , , для .Действительно, пусть — минимально возможное число узлов, включая самого себя, в тонком дереве ранга . По свойствам и тонкого дерева получаем следующие соотношения:для Числа Фибоначчи удовлетворяют этому же рекуррентному соотношению, причем неравенство можно заменить равенством. Отсюда по индукции следует, что для любых . Неравенство хорошо известно.Теперь убедимся в том, что максимально возможный ранг Отсюда следует, что тонкого дерева в тонкой куче, содержащей элементов, не превосходит числа . Действительно, выберем в тонкой куче дерево максимального ранга. Пусть — количество вершин в этом дереве, тогда . . |
Представление тонкой кучи
Тонкую кучу можно представить как односвязный список корней тонких деревьев, причем корень с минимальным ключом должен быть первым в списке.
Поскольку при работе с тонкой кучей ссылка на родителя требуется только у самого левого его ребенка, можно хранить ее вместо ссылки на левого брата этой вершины.
Таким образом, для эффективной работы тонкой кучи необходимы следующие поля узла:
- — ключ (вес) элемента;
- — указатель на самого левого ребенка узла;
- — указатель на правого брата узла, либо на следующий корень, если текущий узел корень;
- — указатель на левого брата узла, либо на родителя, если текущий узел самый левый, либо null, если это корень;
- — ранг узла (количество дочерних узлов данного узла).
Для ускорения проверки на тонкость (thinness) можно отдельно хранить помеченность вершины. Также в вершине можно хранить любую дополнительную информацию.
Для работы с тонкой кучей достаточно иметь односвязный список ее корней.
Операции над тонкой кучей
Рассмотрим операции, которые можно производить над тонкой кучей. Время работы указано в таблице:
Многие операции над тонкой кучей выполняются так же, как и над фиббоначиевой.
Для амортизационного анализа операций применим метод потенциалов.
Пусть функция потенциала определена как
где — это количество тонких деревьев в куче, а — это количество помеченных вершин.Утверждение: |
Определённый таким образом потенциал обладает свойствами:
|
makeHeap
Для создания новой пустой тонкой кучи нужно вернуть ссылку на новый пустой корневой список, его потенциал
.Стоимость
.insert
Для вставки элемента в тонкую кучу нужно создать новое тонкое дерево из единственного узла с ключом
, добавить его в корневой список на первое место, если этот ключ минимален, иначе на второе. Потенциал увеличивается на 1.Стоимость
.getMin
Для обращения к минимальному элементу в тонкой куче нужно обратиться к первому корневому узлу списка и вернуть его ключ, потенциал
не меняется.Стоимость
.meld
Для объединения тонких куч нужно слить их корневые списки, ставя первым тот список, у которого ключ первого корня минимален. Суммарный потенциал
не меняется.Стоимость
.extractMin
Чтобы извлечь минимальный элемент из тонкой кучи нужно:
- Удалить корень с минимальным ключом из корневого списка.
- Уменьшить ранг для всех его помеченных детей.
- Cлить детей с корневым списком.
- Объединять, пока возможно, тонкие деревья одного ранга.
Это можно сделать, например, с помощью вспомогательного массива размером
, в -ой ячейке которого хранится корень тонкого дерева ранга .Изначально массив пуст, а мы добавляем в него все деревья нашего корневого списка.
При добавлении нового дерева мы, если дерево такого ранга уже есть в массиве, связываем его с существующим и пытаемся добавить новое дерево с рангом на
больше.Пусть мы сделали
связывающих шагов (linking steps) во время добавления в массив.Мы удалили корень из списка за
, затем за нормализовали детей корня и добавили в корневой список, далее за получили новый корневой список, в котором за нашли минимальный корень и подвесили список за него.Получили фактическую стоимость
. С другой стороны, при добавлении детей в список мы увеличили потенциал не более чем на , а каждый связывающий шаг уменьшает наш потенциал на .Cтоимость
.decreaseKey
Чтобы уменьшить ключ элемента нужно:
Стоимость
.delete
Чтобы удалить элемент из тонкой кучи нужно сначала выполнить
этого элемента до , а затем выполнить .Стоимость
.