Биномиальная куча — различия между версиями
Gr1n (обсуждение | вклад) (→Операции над биномиальными кучами) |
Gr1n (обсуждение | вклад) (→Операции над биномиальными кучами) |
||
Строка 66: | Строка 66: | ||
{| border="1" | {| border="1" | ||
|insert | |insert | ||
− | |<tex> | + | |<tex>\Omega(\log(n))</tex> |
|- | |- | ||
|getMinimum | |getMinimum |
Версия 18:49, 10 марта 2012
Содержание
Биномиальное дерево
Определение: |
Биномиальное дерево дерево, определяемое для каждого следующим образом: — дерево, состоящее из одного узла высоты , то есть состоит из одного узла; состоит из двух биномиальных деревьев , связанны вместе таким образом, что корень одного из них является крайним левым дочерним узлом корня второго дерева. | —
Свойства биномиальных деревьев
Утверждение: |
Биномиальное дерево с вершинами имеет узлов |
Так как в дереве порядка | вдвое больше узлов, чем в дереве порядка , а в дереве нулевого порядка узел, то дерево порядка имеет узлов.
Утверждение: |
Биномиальное дерево с вершинами имеет высоту ; |
Так как в дереве порядка | высота больше на (так как мы подвешиваем к текущему дереву дерево того же порядка), чем в дереве порядка , а в дереве нулевого порядка высота , то дерево порядка имеет высоту .
Утверждение: |
Биномиальное дерево с вершинами имеет ровно узлов на высоте ; |
Докажем по индукции: База Рассмотрим — верно. Пусть для некоторого условие верно, то докажем, что для это также верно: уровень дерева . Дерево было получено подвешиванием одного дерева порядка к другому. Тогда на уровне дерева всего узлов , так как от подвешенного дерева в дерево порядка нам пришли узлы глубины . То для -го уровня дерева количество узлов . То свойство доказано. |
Утверждение: |
Биномиальное дерево с вершинами имеет корень степени ; степень всех остальных вершин меньше степени корня биномиального дерева; |
Так как в дереве порядка | степень корня больше на , чем в дереве порядка , а в дереве нулевого порядка степень корня , то дерево порядка имеет корень степени . И так как при таком увеличении порядка(при переходе от дерева порядка к ) в полученном дереве лишь степень корня возрастает, то доказываемый инвариант, то есть степень корня больше степени остальных вершин, не будет нарушаться.
Утверждение: |
В биномиальном дереве с вершинами максимальная степень произвольного узла равна . |
Докажем это утверждение для корня. Степень остальных вершин меньше по предыдущему свойству. Так как степень корня дерева порядка | равна , а узлов в этом дереве , то прологарифмировав обе части получаем, что , то степень произвольного узла не более .
Биномиальная куча
Определение: |
Биномиальная пирамида — представляет собой множество биномиальных деревьев, которые удовлетворяют следующим свойствам:
|
Представление биномиальных куч
Поскольку количество детей у узлов варьируется в широких пределах, ссылка на детей осуществляется через левого ребенка, а остальные дети образуют односвязный список. Каждый узел в биномиальной пирамиде (куче) представляется набором полей:
- — ключ (вес) элемента;
- — указатель на родителя узла;
- — указатель на левого ребенка узла;
- — указатель на правого брата узла;
- — степень узла (количество дочерних узлов данного узла).
Корни деревьев, их которых состоит пирамида, содержатся в так называемом списке корней, при проходе по которому степени соответствующих корней находятся в возрастающем порядке. Доступ к куче осуществляется ссылкой на первый корень в списке корней.
Операции над биномиальными кучами
Рассмотрим операции, которые можно производить с биномиальной пирамидой. Время работы указано в таблице:
insert | |
getMinimum | |
extractMin | |
merge | |
decreaseKey | |
delete |
Обозначим нашу кучу за
. То пусть — указатель на корень биномиального дерева минимального порядка этой кучи. Изначально , то есть пирамида не содержит элементов.getMinimum
Для нахождения минимального элемента надо найти элемент в списке корней с минимальным значением (предполагается, что ключей, равных
, нет).Так как корней в этом списке не более
, то операция выполняется за .При вызове этой процедуры для кучи, изображенной на картинке ниже, будет возвращен указатель на вершину с ключем
.merge
Эта операция, соединяющая две биномиальные кучи в одну, используется в качестве подпрограммы большинством остальных операций.
Вот в чем состоит ее суть: пусть есть две биномиальные кучи с
и . Размеры деревьев в кучах соответствуют двоичным числам и , то есть при наличии дерева соответствующего порядка в этом разряде числа стоит единица, иначе ноль. При сложении столбиком в двоичной системе происходят переносы, которые соответствуют слияниям двух биномиальных деревьев в дерево . Надо только посмотреть, в каком из сливаемых деревьев корень меньше, и считать его верхним(пример работы этого действия приведен на рисунке справа).
Работа этой процедуры начинается с соединения корневых списков куч в единый список, в котором корневые вершины идут в порядке неубывания их степеней.
В получившемся списке могут встречаться пары соседних вершин одинаковой степени. Поэтому мы начинаем соединять деревья равной степени и делаем это до тех пор, пока деревьев одинаковой степени не останется. Этот процесс соответствует сложению двоичных чисел столбиком, и время его работы пропорционально числу корневых вершин, то есть операция выполняется за
.insert
Чтобы добавить новый элемент в биномиальную кучу нужно создать биномиальную пирамиду
с единственным узлом, содержащим этот элемент, за время и объединить ее с биномиальной пирамидой за .extractMin
Приведенная ниже процедура извлекает узел с минимальным ключом из биномиальной кучи и возвращает указатель на извлеченный узел.
Рассмотрим пошагово алгоритм:
- Найдем биномиальное дерево с минимальным корневым значением. Предположим, что это дерево . Время работы этого шага алгоритма .
- Удаляем дерево из кучи . Иными словами удаляем его корень из списка корней кучи. Это можно сделать за время .
- Переберем детей удаленного корня, причем в ходе перебора устанавливаем указатель на предка равным . Для каждого ребенка создадим новое дерево , которое сливаем с кучей за O(log n).
Процедура выполняется за время
, поскольку всего в списке корней биномиальных деревьев. И всего у найденного дерева порядка(с минимальным значением ключа) ровно детей, то сложность перебора этих детей будет тоже . Таким образом операция выполняется .
Node extractMin(H) {
//поиск корня х с минимальным значением ключа в списке корней Н:
min =
;
x = null;
curx = H.head;
while curx != null {
// релаксируем текущий минимум
if curx.key < min {
min = curx.key;
x = curx;
}
curx = curx.next;
}
//удаление найденного корня x из списка корней деревьев кучи
x.prev.next = x.next;
x.next.prev = x.prev;
//добавление детей узла x в кучу:
H' = null;
curx = x.child;
while curx != null {
// меняем указатель на родителя узла curx
p[curx] = null;
// инициализация вспомогательного дерева H'
H'.head = curx;
// слияние нашего дерева с текущим деревом H'
H = merge(H, H');
// переход к следующему ребенку
curx = curx.sibling;
}
return x;
}
Поскольку минимальный элемент находится в корневом списке, найти его легко; после его удаления соответствующее дерево рассыпается в набор биномиальных деревьев меньшего размера, который нужно объединить с оставшейся частью кучи. Все действия выполняются за время
, так что общее время работы процедуры есть .decreaseKey
Следующая процедура уменьшает ключ элемента
биномиальной кучи, присваивая ему новое значение. Вершина, ключ которой был уменьшен, «всплывает» наверх, то есть алгоритм состоит в том, что текущий элемент, в случае его минимальности относительно его родителя, на каждом шаге меняться с этим родителем, и указатель на текущую вершину меняется соответственно на родителя, с которым поменяли. Процедура выполняется за время , поскольку глубина вершины есть (свойства биномиального дерева), а при выполнении каждого шага алгоритма мы поднимаемся вверх.
void decreaseKey(H, x, k) { // проверка на то, что текущий ключ не меньше передаваемого ключа 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
Удаление ключа сводится к операциям decreaseKey и extractMin: сначала нужно уменьшить ключ до минимально возможного значения, а затем извлечь вершину с минимальным ключом. В процессе выполнения процедуры этот узел всплывает вверх, откуда и удаляется. Процедура выполняется за время
, поскольку каждая из операций, которые используется в реализаций, работают за .
void delete(H, x) {
//уменшение ключа до минимально вохможного значения
decreaseKey(H, x,
);
//удаление "всплывшего" элемента
extractMin(H);
}
Источники
- Биномиальные кучи — INTUIT.ru
- Binomial heap — Wikipedia
- Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд. — М.: «Вильямс», 2007. — с. 538—558. — ISBN 5-8489-0857-4