Биномиальная куча
Свойства биномиальных деревьев(с доказательством).
Биномиальное дерево
с n вершинами:- имеет узлов;
В силу того, что с увеличением порядка дерева на
количество узлов увеличивается вдвое, а изначально дерево имеет узел, то при любом , дерево порядка имеет узлов.- имеет высоту ;
В силу того, что с увеличением порядка дерева на
, мы подвешиваем к текущему дереву дерево того же порядка, то высота получившегося в результате слияния дерева увеличивается на . Изначально имеем высоту узел, то при любом , дерево порядка имеет высоту .- имеет ровно узлов на высоте ;
- имеет корень степени ; степерь всех остальных вершин меньше степени корня биномиального дерева;
- максимальная степень произвольного узла в биномиальном дереве с n узлами равна .
Определение: |
Биномиальная пирамида (куча) — представляет собой множество биномиальных деревьев, которые удовлетворяют следующим свойствам :
|
Представление биномиальных куч
Поскольку количество детей у узлов варьируется в широких пределах, ссылка на детей осуществляется через левого ребенка, а остальные дети образуют односвязный список. Каждый узел в биномиальной пирамиде (куче) представляется набором полей:
- — ключ (вес) элемента;
- — указатель на родителя узла;
- — указатель на левого ребенка узла;
- — указатель на правого брата узла;
- — степень узла (количество дочерних узлов данного узла).
Корни деревьев, их которых состоит пирамида, содержатся в так называемом списке корней, при проходе по которому степени соответствующих корней находятся в неубывающем порядке. Доступ к куче осуществляется ссылкой на первый корень в списке корней.
Операции над биномиальными пирамидами
Рассмотрим операции, которые можно производить с биномиальной пирамидой. Их асимптотические оценки показаны в таблице.
insert | |
getMinimum | |
extractMin | |
merge | |
decreaseKey | |
delete |
Обозначим нашу кучу за
. То пусть — указатель на корень биномиального дерева минимального порядка этой кучи. Изначально , то есть пирамида не содержит элементов.getMinimum
Для нахождения минимального элемента надо найти элемент в списке корней с минимальным значением (предполагается, что ключей, равных
, нет).Асимптотика этой операции получается из того, что корней в этом списке не более
.При вызове этой процедуры для кучи, изображенной на картинке ниже, будет возвращен указатель на вершину с ключем
.merge
Эта операция, соединяющая две биномиальные кучи в одну, используется в качестве подпрограммы большинством остальных операций.
Для этого нам надо сначала слить списки корней
в единый связный список, отсортированный по степеням в монотонно возрастающем порядке. Свойство пирамиды обеспечивает нам в новом списке наличие не более двух деревьев одинаковой степени. Далее мы за один проход по этому списку объединим некоторые деревья так, что в результате все они будут иметь попарно разные степени. На каждом шаге нам надо расмотреть несколько случаев.- Рассматриваемое дерево и следующее за ним имеют разные степени (случай на рисунке). Ситуация тривиальна и не требует никаких действий. Переходим к следующему шагу.
- Текущее дерево и его два ближаших соседа справа (то есть те, которые встретятся на последующих итерациях) имеют одинаковые степени (случай на рисунке). Эта ситуация хоть и не тривиальна, но ее следует оставить для следующего шага.
- Если степень текущего и последующего деревьев одинакова (случай на рисунке), то нам следует объединить их в новое дерево (сделав корнем вершину того дерева, чей ключ наименьший), степень которого будет на единицу больше той, что была ранее.
Пример пирамиды до merge и после:
insert
Необходимо просто создать биномиальную пирамиду
с одним узлом за время и объединяет ее с биномиальной пирамидой , содержащей узлов, за время .extractMin
Приведенная ниже процедура извлекает узел с минимальным ключом из биномиальной кучи и возвращает указатель на извлеченный узел:
Node extractMin(H) { //поиск корня х с минимальным значением ключа в списке корней Н, и удаление х из корней Н min =; x = null; curx = head[H]; while curx null { if curx.key < min { min = curx.key; x = curx; } curx = curx.next; } x.prev.next = x.next; x.next.prev = x.prev; //добавление детей элемента x в кучу. H' = null; curx = x.child; while curx null { p[curx] = null; head[H'] = curx; H = merge(H, H'); curx = curx.sibling; } return x; }
Поскольку минимальный элемент находится в корневом списке, найти его легко; после его удаления соответствующее дерево рассыпается в набор биномиальных деревьев меньшего размера, который надо объединить с оставшейся частью кучи. Все действия выполняются за время
, так что общее время работы процедуры есть .decreaseKey
Следующая процедура уменьшает ключ элемента
биномиальной кучи, присваивая ему новое значение. Вершина, ключ которой был уменьшен, «всплывает» наверх. Процедура выполняется за время , поскольку глубина вершины есть (свойства биномиального дерева), а при выполнении каждого шага алгоритма мы поднимаемся вверх.
void decreaseKey(H, x, k) {
if k > key[x] then
return;
key[x] = k;
y = x;
z = p[y];
//поднимаем текущий элемент x с новым ключом k, пока
//это значение меньше значения в родительской вершине
while z
null and key[y] < key[z] do {
swap(key[y], key[z]);
y = z;
z = p[y];
}
}
Пример работы процедуры проиллюстрирован на рисунке (
— уменьшаемый элемент, — его предок).delete
Удаление ключа сводится к двум предыдущим операциям: мы уменьшаем ключ до минимально возможного значения, а затем удаляем вершину с минимальным ключом. В процессе выполнения процедуры это значение всплывает вверх, откуда и удаляется. Процедура выполняется за время
.
void delete(H, x) {
//уменшение ключа до минимально вохможного значения
decreaseKey(H, x, -
);
//удаление "всплывшего" элемента
extractMin(H);
}
Источники
- Биномиальные кучи — INTUIT.ru
- Binomial heap — Wikipedia
- Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд. — М.: «Вильямс», 2007. — с. 538-558. — ISBN 5-8489-0857-4