Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Лекция 10. Биномиальные кучи (Binomial heaps)
1. Лекция 10Биномиальные кучи(Binomial heaps)
КурносовМихаил Георгиевич
E-mail: mkurnosov@gmail.com
WWW: www.mkurnosov.net
Курс “Алгоритмы и структуры данных”
Сибирский государственный университет телекоммуникаций и информатики (Новосибирск)
Осенний семестр, 2014
2. Значение (Value)
Приоритет(Priority)
Слон
3
Кит
1
Лев
15
Очередь с приоритетом (Priority queue)
2
Очередь с приоритетом (Priority queue) – это очередь, в которой элементы имеют приоритет (вес)
Поддерживаемые операции:
oInsert(key, value)–добавляет в очередь значение valuec приоритетом (весом, ключом) key
oDeleteMin/DeleteMax–удаляет из очереди элемент с мин./макс. приоритетом (ключом)
oMin/Max–возвращает элемент с мин./макс. ключом
oDecreaseKey–изменяет значение ключа заданного элемента
oMerge(q1, q2)–сливает две очереди в одну
3. Двоичная куча (Binary heap)
3
Двоичная куча (пирамида, сортирующее дерево, binary heap) –это двоичное дерево, удовлетворяющее следующим условиям:
a)приоритет(ключ) любой вершины не меньше ( ≥), приоритета её потомков
b)дерево является полным двоичным деревом (complete binary tree)– все уровни заполнены, возможно за исключением последнего
max-heap
4. Двоичная куча (Binary heap)
4
max-heap
Приоритет любой вершины не меньше (≥), приоритета потомков
min-heap
Приоритет любой вершины не больше (≤), приоритета потомков
5. Очередь с приоритетом (Priority queue)
5
В таблице приведены трудоемкости операций очереди с приоритетом (в худшем случае, worst case)
Символом ‘*’ отмечена амортизированная сложность операций
Операция
Binary heap
Binomialheap
Fibonacci heap
Pairing heap
Brodalheap
FindMin
Θ(1)
O(logn)
Θ(1)
Θ(1)*
Θ(1)
DeleteMin
Θ(logn)
Θ(logn)
O(logn)*
O(logn)*
O(logn)
Insert
Θ(logn)
O(logn)
Θ(1)
Θ(1)*
Θ(1)
DecreaseKey
Θ(logn)
Θ(logn)
Θ(1)*
O(logn)*
Θ(1)
Merge/Union
Θ(n)
Ω(logn)
Θ(1)
Θ(1)*
Θ(1)
6. Биномиальные кучи (Binomial heaps)
6
Биномиальная куча (Binomial heap, пирамида) – это эффективно сливаемая куча(mergeableheap)
В биномиальной куче слияние (merge, union)двух куч выполняется за время O(logn)
Биномиальные кучи формируются на основе биномиальных деревьев (binomial trees)
7. Биномиальное дерево (Binomial tree)
7
Биномиальное дерево Bk (Binomial tree) – это рекурсивно определяемое деревовысоты k, в котором:
oколичество узлов равно 2k
oколичество узлов на уровне i= 0, 1, …, k 푘 푖 = 푘! 푖!푘−푖! (количество сочетаний из k по i)
oкорень имеетk дочерних узлов:
−первый дочерний узел (самый левый) –дерево Bk-1
−второй дочерний узел (второй слева) –дерево Bk-2
−…
−k-й дочерний узел (самый правый) –дерево B0
9. Биномиальная куча (Binomial heap)
9
Биномиальная куча (Binomial heap) – это множество биномиальных деревьев, которые удовлетворяют свойствам биномиальных куч:
1)каждое биномиальноедерево упорядочено (ordered) в соответствии со свойствами неубывающейили невозрастающей кучи (min-heap/max-heap): ключ узла не меньше/не больше ключа его родителя
2)для любого целого k≥ 0в куче имеется не более одногобиномиального дерева, чей корень имеет степень k
Биномиальная куча содержащая nузлов состоит не более чем изlog(푛)+1биномиальных деревьев
15. Поиск минимальногоузла(FindMin)
15
В корне каждого биномиального дерева хранится его минимальный/максимальный ключ
Для поиска минимального/максимального элемента в биномиальной куче требуется пройти по спискуизlog(푛)+1корней
6
29
14
38
8
17
11
27
1
25
12
18
10
Head
16. Поиск минимальногоузла(FindMin)
16
functionBinomialHeapMin(heap)
x = heap
min.key= Infinity
whilex != NULL do
ifx.key< min.keythen
min = x
x = x.sibling
end while
returnmin
end function
6
29
14
38
8
17
11
27
1
25
12
18
10
Head
TMin= O(logn)
17. functionBinomialHeapMin(heap)
x = heap
min.key= Infinity
whilex != NULL do
ifx.key< min.keythen
min = x
x = x.sibling
end while
returnmin
end function
Поиск минимальногоузла(FindMin)
17
6
29
14
38
8
17
11
27
1
25
12
18
10
Head
Как реализовать поиск минимального/максимального ключа за время O(1)?
Поддерживать указатель на корень дерева (узел), в котором находится экстремальный ключ
TMin= O(logn)
18. Слияние куч(Union)
18
Для слияния (union, merge)двух куч H1и H2в новую кучу Hнеобходимо:
1.Слить списки корней H1и H2в один упорядоченный список
2.Восстановить свойства биномиальной кучи H
После слияния списков корней известно, что в куче Hимеется не более двух корней с одинаковой степенью и они соседствуют
21. Слияние списков корней
functionBinomialHeapListMerge(h1, h2)
h = NULL
whileh1 != NULL && h2 != NULL do
if h1.degree <= h2.degree then
LinkedList_AddEnd(h, h1)
h1 = h1.next
else
LinkedList_AddEnd(h, h2)
h2 = h2.next
end if
end while
whileh1 != NULL do
LinkedList_AddEnd(h, h1)
h1 = h1.next
end while
whileh2 != NULL do
LinkedList_AddEnd(h, h2)
h2 = h2.next
end while
returnh
end function
TListMerge=O(log(max(n1, n2)))
21
22. Слияние куч (Union)
22
6
44
10
17
29
31
48
50
3
37
18
8
22
23
24
30
32
45
55
15
33
28
41
7
25
12
H
Ситуация после слияния списков корней
Свойство 1 биномиальной кучи выполняется
Свойство 2 не выполняется:два дерева B0и два дерева B1
B0
B0
B1
B1
B2
B4
23. 23
Случай 3
x.degree= next-x.degree≠next-x.sibling.degreex.key≤ next-x.key
a
b
c
prev-x
x
next-x
d
a
b
c
prev-x
x
next-x
d
Bk
Bk
Bl
Bk
Bk
Bl
Bk+1
x.sibling= next-x.sibling
BinomialTreeLink(next-x, x)
next-x = x.sibling
27. Случай 2
27
a
b
c
prev-x
x
next-x
d
a
b
c
prev-x
x
next-x
d
Bk
Bk
Bk
Bk
Bk
Bk
x.degree= next-x.degree=next-x.sibling.degree
/* Перемещаем указатели по списку корней */
prev-x = x
x = next-x
next-x = x.sibling
28. Случай 2
28
x.degree= next-x.degree=next-x.sibling.degree
/* Перемещаем указатели по списку корней */
prev-x = x
x = next-x
next-x = x.sibling
6
44
10
17
29
31
48
50
3
37
18
8
22
23
24
30
32
45
55
15
33
28
41
7
25
12
H
x
next-x
prev-x
29. 29
prev-x.sibling= next-x
BinomialTreeLink(x, next-x)
x= next-x
next-x = x.sibling
Случай 4
x.degree= next-x.degree≠next-x.sibling.degreex.key> next-x.key
a
b
c
prev-x
x
next-x
d
a
c
b
prev-x
x
next-x
d
Bk
Bk
Bl
Bk
Bk
Bl
Bk+1
30. Случай 1
30
x.degree≠ next-x.degree
Узел x–корень дерева Bk
Узел next-x–корень дерева Bl, l> k
/* Перемещаем указатели по списку корней */
prev-x = x
x = next-x
next-x = x.sibling
a
b
c
prev-x
x
next-x
d
a
b
c
prev-x
x
next-x
d
Bk
Bl
Bk
Bl
l> k
31. Слияние биномиальных куч(Union)
functionBinomialHeapUnion(h1, h2)
h = BinomialHeapListMerge(h1, h2)
prev-x = NULL
x = h
next-x = x.sibling
whilenext-x != NULL do
if(x.degree!= next-x.degree) OR
(next-x.sibling!= NULL AND
next-x.sibling.degree= x.degree)
then
prev-x = x /* Случаи 1 и 2 */
x = next-x
else if x.key<= next-x.keythen
x.sibling= next-x.sibling/* Случай 3 */
BinomialTreeLink(next-x, x)
31
32. Слияние биномиальных куч(Union)
else
/* Случай 4*/
ifprev-x = NULL then
h = next-x
else
prev-x.sibling= next-x
end if
BinomialTreeLink(x, next-x)
x = next-x
end if
next-x = x.sibling
end while
returnh
end function
32
TUnion= O(logn)
33. Слияние биномиальных куч(Union)
33
Вычислительная сложность слияния двух биномиальных куч в худшем случае равна O(log(n))
Длина списка корней не превышает
log(n1) + log(n1) + 2 = O(log(n))
Цикл while в функции BinomialHeapUnionвыполняется не более O(log(n)) раз
На каждой итерации цикла указатель перемещается по списку корней вправо на одну позицию или удаляется один узел –это требует времени O(1)
34. Вставка узла(Insert)
34
Создаем биномиальную кучу из одного узла x– биномиального дерева B0
Сливаем исходную кучу Hи кучу из узла x
functionBinomialHeapInsert(h, key, value)
x.key= key
x.value= value
x.degree= 0
x.parent= NULL
x.child= NULL
x.sibling= NULL
returnBinomialHeapUnion(h, x)
end function
TInsert= O(logn)
35. Удаление минимального узла (DeleteMin)
35
1.В списке корней кучи Hотыскиваем корень xс минимальным ключом и удаляем xиз списка корней (разрывам связь)
2.Инициализируем пустую кучу Z
3.Меняем порядок следования дочерних узлов корня хна обратный, у каждого дочернего узла устанавливаем поле parent в NULL
4.Устанавливаем заголовок кучи Zна первый элемент нового списка корней
5.Сливаем кучи Hи Z
6.Возвращаем x
39. Удаление минимального узла (DeleteMin)
functionBinomialHeapDeleteMin(h)
/* Lookup and unlink min node */
x = h
xmin.key= Infinity
prev= NULL
whilex != NULL do
ifx.key< xmin.keythen
xmin= x
prevmin= prev
end if
prev= x
x = x.sibling
end while
ifprevmin!= NULL then
prevmin.sibling= xmin.sibling
else
h = xmin.sibling
39
40. Удаление минимального узла (DeleteMin)
/* Reverse linked list */
child = xmin.child
prev= NULL
whilechild != NULL do
sibling = child.sibling
child.sibling= prev
prev= child
child = sibling
end while
returnBinomialHeapUnion(h, prev)
end function
40
TDeleteMin= O(logn)
41. Уменьшение ключа (DecreaseKey)
41
1.Получаем указатель на узел xи изменяем у него ключ (newkey<= x.key)
2.Проверяем значение ключа родительского узла, если он меньше ключа x, то выполняем обмен ключей(и данных), повторяем обмены пока не поднимемся до корня текущего биномиального дерева
6
29
14
38
8
17
5
27
1
25
12
18
10
Head
x
p
42. Уменьшение ключа (DecreaseKey)
42
functionBinomialHeapDecreaseKey(h, x, key)
ifx.key< k then
returnError
x.key= key
y = x
z = y.parent
whilez != NULL ANDy.key< z.keydo
temp = y.key
y.key= z.key
z.key= temp
y = z
z = y.parent
end while
end function
TDecreaseKey= O(logn)
43. Удаление узла (Delete)
43
functionBinomialHeapDelete(h, x)
BinomialHeapDecreaseKey(h, x, -Infinity)
BinomialHeapDeleteMin(h)
end function
TDelete= O(logn)