Биномиальная куча - Википедия - Binomial heap
В Информатика, а биномиальная куча это структура данных что действует как приоритетная очередь но также позволяет объединять пары куч. Это важно как реализация объединяемая куча абстрактный тип данных (также называемый плавная куча ), что является приоритетная очередь поддержка операции слияния. Он реализован как куча похожий на двоичная куча но используя специальную древовидную структуру, отличную от полные бинарные деревья используется двоичными кучами.[1] Биномиальные кучи были изобретены в 1978 году Жан Вюйлемен.[1][2]
Биномиальная куча
Биномиальная куча реализована как набор биномиальный деревья (сравните с двоичная куча, имеющий форму одиночного двоичное дерево ), которые рекурсивно определяются следующим образом:[1]
- Биномиальное дерево порядка 0 - это единственный узел
- Биномиальное дерево порядка имеет корневой узел, дети которого являются корнями биномиальных деревьев порядков , , ..., 2, 1, 0 (в таком порядке).
Биномиальное дерево порядка имеет узлы и высота . Название происходит от формы: биномиальное дерево порядка. имеет узлы на глубине , а биномиальный коэффициент.Биномиальное дерево порядка из-за своей структуры можно построить из двух деревьев порядка присоединяя один из них как крайний левый дочерний элемент корня другого дерева. Эта функция занимает центральное место в слияние работа биномиальной кучи, что является ее основным преимуществом перед другими обычными кучами.[1][3]
Структура биномиальной кучи
Биномиальная куча реализуется как набор биномиальных деревьев, удовлетворяющих биномиальные свойства кучи:[1]
- Каждое биномиальное дерево в куче подчиняется свойство с минимальной кучей: ключ узла больше или равен ключу его родителя.
- Может быть только либо один или же нуль биномиальные деревья для каждого порядка, включая нулевой порядок.
Первое свойство гарантирует, что корень каждого биномиального дерева содержит наименьший ключ в дереве. Отсюда следует, что самый маленький ключ во всей куче - это один из корней.[1]
Второе свойство означает, что биномиальная куча с узлов состоит не более чем из биномиальные деревья, где это двоичный логарифм. Количество и порядок этих деревьев однозначно определяются количеством узлов. : есть одно биномиальное дерево для каждого ненулевого бита в двоичный представление числа . Например, десятичное число 13 в двоичном формате равно 1101, , и, таким образом, биномиальная куча с 13 узлами будет состоять из трех биномиальных деревьев порядков 3, 2 и 0 (см. рисунок ниже).[1][3]
Пример биномиальной кучи, содержащей 13 узлов с разными ключами.
Куча состоит из трех биномиальных деревьев с порядками 0, 2 и 3.
Количество различных способов элементы с разными ключами могут быть расположены в биномиальную кучу, равную наибольшему нечетному делителю . За эти числа
Если элементы вставляются в биномиальную кучу в равномерно случайном порядке, каждый из этих вариантов одинаково вероятен.[3]
Выполнение
Поскольку никакая операция не требует произвольного доступа к корневым узлам биномиальных деревьев, корни биномиальных деревьев могут храниться в связанный список, упорядоченный по возрастанию порядка дерева. Поскольку количество дочерних узлов для каждого узла является переменным, для каждого узла нецелесообразно иметь отдельные ссылки на каждый из своих дочерних узлов, как это обычно бывает в двоичное дерево; вместо этого можно реализовать это дерево, используя ссылки от каждого узла к его дочернему элементу наивысшего порядка в дереве и к его дочернему элементу следующего меньшего порядка, чем он. Эти одноуровневые указатели можно интерпретировать как следующие указатели в связанном списке дочерних узлов каждого узла, но с порядком, обратным порядку связанного списка корней: от наибольшего к наименьшему, а не наоборот. Это представление позволяет связать два дерева одного порядка вместе, образуя дерево следующего большего порядка за постоянное время.[1][3]
Объединить
Работа слияние две кучи используются в качестве подпрограммы в большинстве других операций. Базовая подпрограмма в этой процедуре объединяет пары биномиальных деревьев одного порядка. Это может быть сделано путем сравнения ключей в корнях двух деревьев (наименьшие ключи в обоих деревьях). Корневой узел с большим ключом превращается в дочерний узел корневого узла с меньшим ключом, увеличивая его порядок на единицу:[1][3]
функция mergeTree (p, q) если p.root.key <= q.root.key возвращаться p.addSubTree (q) еще возвращаться q.addSubTree (p)
Для более общего слияния двух куч списки корней обеих куч просматриваются одновременно аналогично тому, как это делается для алгоритм слияния, в последовательности от меньших порядков деревьев к большим порядкам. Когда только одна из двух объединяемых куч содержит дерево порядка , это дерево перемещается в кучу вывода. Когда обе кучи содержат дерево порядка , два дерева объединяются в одно дерево порядка так что свойство минимальной кучи удовлетворяется. Позже может возникнуть необходимость объединить это дерево с каким-либо другим деревом порядка. в одной из двух входных куч. В ходе алгоритма он будет исследовать не более трех деревьев любого порядка: два из двух куч, которые мы объединяем, и одно, состоящее из двух меньших деревьев.[1][3]
функция объединить (p, q) пока нет (p.end () и q.end ()) tree = mergeTree (p.currentTree (), q.currentTree ()) если нет heap.currentTree (). empty () tree = mergeTree (дерево, heap.currentTree ()) heap.addTree (дерево) heap.next (); p.next (); q.next ()
Поскольку каждое биномиальное дерево в биномиальной куче соответствует биту в двоичном представлении его размера, существует аналогия между объединением двух куч и двоичным сложением размеры из двух куч, справа налево. Когда перенос происходит во время сложения, это соответствует слиянию двух биномиальных деревьев во время слияния.[1][3]
У каждого дерева порядок не более и поэтому время работы .[1][3]
Вставлять
Вставка новый элемент в кучу можно создать, просто создав новую кучу, содержащую только этот элемент, и затем объединя ее с исходной кучей. Из-за слияния для одной вставки требуется время . Однако это можно ускорить с помощью процедуры слияния, которая сокращает слияние после того, как оно достигает точки, где только одна из объединенных куч имеет деревья большего порядка. Благодаря этому ускорению через серию последовательные вставки, общее время вставок равно . Другой способ сформулировать это так: (после логарифмических накладных расходов на первую вставку в последовательности) каждый последующий вставлять имеет амортизированный время из (т.е. константа) на каждую вставку.[1][3]
Вариант биномиальной кучи, косая биномиальная куча, обеспечивает постоянное время вставки в худшем случае за счет использования лесов, размеры деревьев которых основаны на косая двоичная система счисления а не в двоичной системе счисления.[4]
Найдите минимум
Чтобы найти минимум элемент кучи, найдите минимум среди корней биномиальных деревьев. Это можно сделать в время, так как есть только корни деревьев для изучения.[1]
Используя указатель на биномиальное дерево, содержащее минимальный элемент, время этой операции может быть сокращено до . Указатель необходимо обновлять при выполнении любой операции, кроме поиска минимума. Это можно сделать в время на обновление, без увеличения общего асимптотического времени выполнения любой операции.[нужна цитата ]
Удалить минимум
К удалить минимальный элемент из кучи сначала найдите этот элемент, удалите его из корня его биномиального дерева и получите список его дочерних поддеревьев (каждое из которых является биномиальным деревом различного порядка). Преобразуйте этот список поддеревьев в отдельную биномиальную кучу, переупорядочив их от наименьшего к наибольшему порядку. Затем объедините эту кучу с исходной кучей. Поскольку каждый корень имеет не более дети, создание этой новой кучи требует времени . Слияние куч требует времени , поэтому вся минимальная операция удаления требует времени .[1]
функция deleteMin (куча) min = heap.trees (). first () для каждого Текущий в heap.trees () если current.rootтогда min = текущий для каждого дерево в min.subTrees () tmp.addTree (дерево) heap.removeTree (min) merge (куча, tmp)
Клавиша уменьшения
После уменьшение ключ элемента, он может стать меньше ключа его родителя, нарушая свойство минимальной кучи. В этом случае замените элемент его родительским элементом, а также, возможно, его прародителем и так далее, пока свойство минимальной кучи не перестанет нарушаться. Каждое биномиальное дерево имеет высоту не более , так что это занимает время.[1] Однако эта операция требует, чтобы представление дерева включало указатели от каждого узла на его родительский элемент в дереве, что несколько усложняет реализацию других операций.[3]
Удалить
К Удалить элемент из кучи, уменьшите его ключ до отрицательной бесконечности (или, что то же самое, до некоторого значения, меньшего, чем любой элемент в куче), а затем удалите минимум в куче.[1]
Приложения
Смотрите также
- Слабая куча, комбинация структур данных двоичной кучи и биномиальной кучи
Рекомендации
- ^ а б c d е ж грамм час я j k л м п о п q Кормен, Томас Х.; Лейзерсон, Чарльз Э.; Ривест, Рональд Л.; Штейн, Клиффорд (2001) [1990]. «Глава 19: Биномиальные кучи». Введение в алгоритмы (2-е изд.). MIT Press и McGraw-Hill. С. 455–475. ISBN 0-262-03293-7.
- ^ Вюйлемен, Жан (1 апреля 1978 г.). «Структура данных для управления очередями приоритетов». Коммуникации ACM. 21 (4): 309–315. Дои:10.1145/359460.359478.
- ^ а б c d е ж грамм час я j Браун, Марк Р. (1978). «Реализация и анализ биномиальных алгоритмов очереди». SIAM Журнал по вычислениям. 7 (3): 298–319. Дои:10.1137/0207026. МИСТЕР 0483830.
- ^ Бродал, Герт Стёльтинг; Окасаки, Крис (ноябрь 1996 г.), "Оптимальные очереди с чисто функциональным приоритетом", Журнал функционального программирования, 6 (6): 839–857, Дои:10.1017 / s095679680000201x
внешняя ссылка
- Две реализации биномиальной кучи на C (общий и оптимизированный для целочисленных ключей)
- Реализация биномиальной кучи в Haskell
- Реализация биномиальной кучи в Common Lisp