Тонкая куча
Тонкая куча — это структура данных, реализующая приоритетную очередь с теми же асимптотическими оценками, что и фиббоначиева куча, но имеющая большую практическую ценность из-за меньших констант.
Тонкие кучи, как и многие другие кучеобразные структуры, аналогичны биномиальным кучам.
Содержание
Тонкое дерево
| Определение: |
| Тонкое дерево (thin tree) ранга — это дерево, которое может быть получено из биномиального дерева удалением у нескольких внутренних, то есть не являющихся корнем или листом, узлов самого левого сына. |
Заметим, что у листьев детей нет, а если у корня удалить самого левого сына, то превратится в . Ранг тонкого дерева равен количеству детей корня.
Для любого узла в дереве обозначим: — количество детей узла ; — ранг соответствующего узла в биномиальном дереве .
Свойства тонкого дерева
| Утверждение: |
Для любого узла либо , в этом случае говорим, что узел не помечен (полный); либо , в этом случае говорим, что узел помечен (неполный). |
| Утверждение: |
Корень не помечен (полный). |
| Утверждение: |
Для любого узла ранги его детей от самого правого к самому левому равны соответственно . |
| Утверждение: |
Узел помечен тогда и только тогда, если его ранг на 2 больше, чем ранг его самого левого сына, или его ранг равен 1 и он не имеет детей. |
Тонкая куча
| Определение: |
| Тонкий лес (thin forest) — это набор тонких деревьев, ранги которых не обязательно попарно различны. |
| Утверждение: |
Для любого натурального числа существует тонкий лес, который содержит ровно элементов и состоит из тонких деревьев попарно различных рангов. |
| Действительно, любой биномиальный лес является тонким, а для биномиального леса рассматриваемое утверждение справедливо. |
| Определение: |
| Тонкая куча (thin heap) — это кучеобразно нагруженный тонкий лес. |
Пусть — максимально возможный ранг узла в тонкой куче, содержащей элементов.
| Теорема (О максимальном ранге узла): |
В тонкой куче из элементов , где — золотое сечение. |
| Доказательство: |
|
Сначала покажем, что узел ранга в тонком дереве имеет не менее потомков, включая самого себя, где — -е число Фибоначчи, определяемое соотношениями , , для . Действительно, пусть — минимально возможное число узлов, включая самого себя, в тонком дереве ранга . По свойствам и тонкого дерева получаем следующие соотношения: для Числа Фибоначчи удовлетворяют этому же рекуррентному соотношению, причем неравенство можно заменить равенством. Отсюда по индукции следует, что для любых . Неравенство хорошо известно. Теперь убедимся в том, что максимально возможный ранг тонкого дерева в тонкой куче, содержащей элементов, не превосходит числа . Действительно, выберем в тонкой куче дерево максимального ранга. Пусть — количество вершин в этом дереве, тогда . Отсюда следует, что . |
Представление тонкой кучи
Поскольку при работе с тонкой кучей ссылка на родителя требуется только у самого левого ее ребенка, можно хранить ее вместо ссылки на левого сына этой вершины.
Таким образом, для эффективной работы тонкой кучи необходимы следующие поля узла:
- — ключ (вес) элемента;
- — указатель на самого левого ребенка узла;
- — указатель на правого брата узла, либо на следующий корень, если текущий узел корень;
- — указатель на левого брата узла, либо на родителя, если текущий узел самый левый, либо null, если это первый корень списка;
- — ранг узла (количество дочерних узлов данного узла).
Отдельно должен храниться односвязный список корней, корень с минимальным ключом должне быть первым в этом списке.
Для ускорения проверки на тонкость (thinness) можно отдельно хранить помеченность вершины.
Также в вершине можно хранить любую дополнительную информацию.
Операции над тонкой кучей
Рассмотрим операции, которые можно производить с тонкой кучей. Время работы указано в таблице:
Многие операции над тонкой кучей выполняются так же, как и над фиббоначиевой.
makeHeap
Возвращаем новый пустой корневой список. Время .
insert
Создаем новое тонкое дерево из единственного узла с ключом , добавляем в корневой список на первое место, если ключ минимален, иначе на второе. Время .
getMin
Обращаемся к первому корневому узлу списка. Время .
meld
Сливаем корневые списки, ставя первым тот список, где ключ первого корня минимален. Время .
extractMin
Удаляем корень с минимальным ключом из корневого списка, затем для всех его тонких детей уменьшаем ранг и делаем их нормальными, после чего сливаем детей с корневым списком и объединяем, пока возможно, тонкие деревья одного ранга. Время .
decreaseKey
Время .
delete
Сначала выполняем этого элемента до , затем выполняем . Время .