Тонкая куча — различия между версиями
Genyaz (обсуждение | вклад) |
Genyaz (обсуждение | вклад) |
||
Строка 34: | Строка 34: | ||
{{Определение | {{Определение | ||
|id=thin_forest_def. | |id=thin_forest_def. | ||
− | |definition='''Тонкий лес''' {{---}} это набор ''тонких деревьев'', ранги которых не обязательно попарно различны. | + | |definition='''Тонкий лес''' (''thin forest'') {{---}} это набор ''тонких деревьев'', ранги которых не обязательно попарно различны. |
}} | }} | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
{{Утверждение | {{Утверждение | ||
Строка 48: | Строка 41: | ||
|statement=Для любого натурального числа <tex>n</tex> существует тонкий лес, который содержит ровно <tex>n</tex> элементов и состоит из тонких деревьев попарно различных рангов. | |statement=Для любого натурального числа <tex>n</tex> существует тонкий лес, который содержит ровно <tex>n</tex> элементов и состоит из тонких деревьев попарно различных рангов. | ||
|proof=Действительно, любой биномиальный лес является тонким, а для биномиального леса рассматриваемое утверждение справедливо. | |proof=Действительно, любой биномиальный лес является тонким, а для биномиального леса рассматриваемое утверждение справедливо. | ||
+ | }} | ||
+ | |||
+ | {{Определение | ||
+ | |id=thin_heap_def. | ||
+ | |definition='''Тонкая куча''' (''thin heap'') {{---}} это кучеобразно нагруженный ''тонкий лес''. | ||
}} | }} | ||
Строка 55: | Строка 53: | ||
|id=max_rank_th. | |id=max_rank_th. | ||
|about=О максимальном ранге узла | |about=О максимальном ранге узла | ||
− | |statement=В тонкой куче из <tex>n</tex> элементов <tex>D(n) \leqslant \log_{\Phi} n</tex>, где <tex>\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>-е число Фибоначчи, определяемое соотношениями <tex>F_0=1</tex>, <tex>F_1=1</tex>, <tex>F_k=F_{k-2}+F_{k-1}</tex> для <tex>k \geqslant 2</tex>. | |proof=Сначала покажем, что узел ранга <tex>k</tex> в тонком дереве имеет не менее <tex>F_k \geqslant \Phi^{k-1}</tex> потомков, включая самого себя, где <tex>F_k</tex> — <tex>k</tex>-е число Фибоначчи, определяемое соотношениями <tex>F_0=1</tex>, <tex>F_1=1</tex>, <tex>F_k=F_{k-2}+F_{k-1}</tex> для <tex>k \geqslant 2</tex>. | ||
Строка 68: | Строка 66: | ||
Отсюда следует, что <tex>D(n)\leqslant\log_{\Phi}(n)+1</tex>. | Отсюда следует, что <tex>D(n)\leqslant\log_{\Phi}(n)+1</tex>. | ||
}} | }} | ||
+ | |||
+ | == Представление тонкой кучи == | ||
+ | |||
+ | Поскольку при работе с ''тонкой кучей'' ссылка на родителя требуется только у самого левого ее ребенка, можно хранить ее вместо ссылки на левого сына этой вершины. | ||
+ | |||
+ | Таким образом, для эффективной работы ''тонкой кучи'' необходимы следующие поля узла: | ||
+ | *<tex>key</tex> {{---}} ключ (вес) элемента; | ||
+ | *<tex>child</tex> {{---}} указатель на самого левого ребенка узла; | ||
+ | *<tex>right</tex> {{---}} указатель на правого брата узла, либо на следующий корень, если текущий узел корень; | ||
+ | *<tex>left</tex> {{---}} указатель на левого брата узла, либо на родителя, если текущий узел самый левый, либо null, если это первый корень списка; | ||
+ | *<tex>rank</tex> {{---}} ранг узла (количество дочерних узлов данного узла). | ||
+ | |||
+ | Отдельно должен храниться односвязный список корней, корень с минимальным ключом должне быть первым в этом списке. | ||
+ | |||
+ | Для ускорения проверки на ''тонкость'' (''thinness'') можно отдельно хранить помеченность вершины. | ||
+ | |||
+ | Также в вершине можно хранить любую дополнительную информацию. | ||
+ | |||
+ | == Операции над тонкой кучей == | ||
+ | |||
+ | Рассмотрим операции, которые можно производить с тонкой кучей. Время работы указано в таблице: | ||
+ | {| border="1" | ||
+ | |-align="center" | ||
+ | |<tex>makeHeap</tex> | ||
+ | |<tex>O(1)</tex> | ||
+ | |-align="center" | ||
+ | |<tex>insert</tex> | ||
+ | |<tex>O(1)</tex> | ||
+ | |-align="center" | ||
+ | |<tex>getMin</tex> | ||
+ | |<tex>O(1)</tex> | ||
+ | |-align="center" | ||
+ | |<tex>meld</tex> | ||
+ | |<tex>O(1)</tex> | ||
+ | |-align="center" | ||
+ | |<tex>extractMin</tex> | ||
+ | |<tex>O(\log(n))</tex> | ||
+ | |-align="center" | ||
+ | |<tex>decreaseKey</tex> | ||
+ | |<tex>O(1)</tex> | ||
+ | |-align="center" | ||
+ | |<tex>delete</tex> | ||
+ | |<tex>O(\log(n))</tex> | ||
+ | |} | ||
+ | |||
+ | Многие операции над тонкой кучей выполняются так же, как и над фиббоначиевой. | ||
+ | |||
+ | === makeHeap === | ||
+ | |||
+ | Возвращаем новый пустой корневой список. Время <tex>O(1)</tex>. | ||
+ | |||
+ | === insert === | ||
+ | |||
+ | Создаем новое тонкое дерево из единственного узла с ключом <tex>x</tex>, добавляем в корневой список на первое место, если ключ минимален, иначе на второе. Время <tex>O(1)</tex>. | ||
+ | |||
+ | === getMin === | ||
+ | |||
+ | Обращаемся к первому корневому узлу списка. Время <tex>O(1)</tex>. | ||
+ | |||
+ | === meld === | ||
+ | |||
+ | Сливаем корневые списки, ставя первым тот список, где ключ первого корня минимален. Время <tex>O(1)</tex>. | ||
+ | |||
+ | === extractMin === | ||
+ | |||
+ | Удаляем корень с минимальным ключом из корневого списка, затем для всех его тонких детей уменьшаем ранг и делаем их нормальными, после чего сливаем детей с корневым списком и объединяем, пока возможно, тонкие деревья одного ранга. | ||
+ | Время <tex>O(\log(n))</tex>. | ||
+ | |||
+ | === decreaseKey === | ||
+ | |||
+ | Время <tex>O(1)</tex>. | ||
+ | |||
+ | === delete === | ||
+ | Сначала выполняем <tex>decreaseKey</tex> этого элемента до <tex>-\infty</tex>, затем выполняем <tex>extractMin</tex>. Время <tex>O(\log(n))</tex>. | ||
+ | |||
= Источники = | = Источники = |
Версия 10:09, 23 мая 2013
Тонкая куча — это структура данных, реализующая приоритетную очередь с теми же асимптотическими оценками, что и фиббоначиева куча, но имеющая большую практическую ценность из-за меньших констант.
Тонкие кучи, как и многие другие кучеобразные структуры, аналогичны биномиальным кучам.
Содержание
Тонкое дерево
Определение: |
Тонкое дерево (thin tree) | ранга — это дерево, которое может быть получено из биномиального дерева удалением у нескольких внутренних, то есть не являющихся корнем или листом, узлов самого левого сына.
Заметим, что у листьев детей нет, а если у корня удалить самого левого сына, то превратится в . Ранг тонкого дерева равен количеству детей корня.
Для любого узла
в дереве обозначим: — количество детей узла ; — ранг соответствующего узла в биномиальном дереве .Свойства тонкого дерева
Утверждение: |
Для любого узла либо , в этом случае говорим, что узел не помечен (полный); либо , в этом случае говорим, что узел помечен (неполный). |
Утверждение: |
Корень не помечен (полный). |
Утверждение: |
Для любого узла ранги его детей от самого правого к самому левому равны соответственно . |
Утверждение: |
Узел помечен тогда и только тогда, если его ранг на 2 больше, чем ранг его самого левого сына, или его ранг равен 1 и он не имеет детей. |
Тонкая куча
Определение: |
Тонкий лес (thin forest) — это набор тонких деревьев, ранги которых не обязательно попарно различны. |
Утверждение: |
Для любого натурального числа существует тонкий лес, который содержит ровно элементов и состоит из тонких деревьев попарно различных рангов. |
Действительно, любой биномиальный лес является тонким, а для биномиального леса рассматриваемое утверждение справедливо. |
Определение: |
Тонкая куча (thin heap) — это кучеобразно нагруженный тонкий лес. |
Пусть — максимально возможный ранг узла в тонкой куче, содержащей элементов.
Теорема (О максимальном ранге узла): |
В тонкой куче из элементов , где — золотое сечение. |
Доказательство: |
Сначала покажем, что узел ранга в тонком дереве имеет не менее потомков, включая самого себя, где — -е число Фибоначчи, определяемое соотношениями , , для .Действительно, пусть — минимально возможное число узлов, включая самого себя, в тонком дереве ранга . По свойствам и тонкого дерева получаем следующие соотношения:для Числа Фибоначчи удовлетворяют этому же рекуррентному соотношению, причем неравенство можно заменить равенством. Отсюда по индукции следует, что для любых . Неравенство хорошо известно.Теперь убедимся в том, что максимально возможный ранг Отсюда следует, что тонкого дерева в тонкой куче, содержащей элементов, не превосходит числа . Действительно, выберем в тонкой куче дерево максимального ранга. Пусть — количество вершин в этом дереве, тогда . . |
Представление тонкой кучи
Поскольку при работе с тонкой кучей ссылка на родителя требуется только у самого левого ее ребенка, можно хранить ее вместо ссылки на левого сына этой вершины.
Таким образом, для эффективной работы тонкой кучи необходимы следующие поля узла:
- — ключ (вес) элемента;
- — указатель на самого левого ребенка узла;
- — указатель на правого брата узла, либо на следующий корень, если текущий узел корень;
- — указатель на левого брата узла, либо на родителя, если текущий узел самый левый, либо null, если это первый корень списка;
- — ранг узла (количество дочерних узлов данного узла).
Отдельно должен храниться односвязный список корней, корень с минимальным ключом должне быть первым в этом списке.
Для ускорения проверки на тонкость (thinness) можно отдельно хранить помеченность вершины.
Также в вершине можно хранить любую дополнительную информацию.
Операции над тонкой кучей
Рассмотрим операции, которые можно производить с тонкой кучей. Время работы указано в таблице:
Многие операции над тонкой кучей выполняются так же, как и над фиббоначиевой.
makeHeap
Возвращаем новый пустой корневой список. Время
.insert
Создаем новое тонкое дерево из единственного узла с ключом
, добавляем в корневой список на первое место, если ключ минимален, иначе на второе. Время .getMin
Обращаемся к первому корневому узлу списка. Время
.meld
Сливаем корневые списки, ставя первым тот список, где ключ первого корня минимален. Время
.extractMin
Удаляем корень с минимальным ключом из корневого списка, затем для всех его тонких детей уменьшаем ранг и делаем их нормальными, после чего сливаем детей с корневым списком и объединяем, пока возможно, тонкие деревья одного ранга. Время
.decreaseKey
Время
.delete
Сначала выполняем
этого элемента до , затем выполняем . Время .