Upload
mikhail-kurnosov
View
838
Download
0
Embed Size (px)
Citation preview
Лекция 7Бинарные кучи (пирамиды)
Курносов Михаил Георгиевич
к.т.н. доцент Кафедры вычислительных систем Сибирский государственный университет
телекоммуникаций и информатики
http://www.mkurnosov.net/teaching
2
Значение (Value) Приоритет (Priority)
Слон 3
Кит 1
Лев 15
Очередь с приоритетом (Priority queue)
Очередь с приоритетом (Priority queue) –очередь, в которой элементы имеют приоритет (вес); первым извлекается элемент с большим/меньшим приоритетом
Поддерживаемые операции:
Insert – добавление элемента в очередь
DeleteMin/DeleteMax – удаляет из очереди элемент с мин./макс. приоритетом
Min/Max – возвращает элемент с мин./макс. приоритетом
DecreaseKey – изменяет значение приоритета элемента
Merge – сливает две очереди в одну
Бинарная куча (Binary heap)
3
Бинарная куча (пирамида, сортирующее дерево, binary heap) – это двоичное дерево, удовлетворяющее следующим условиям:
a) приоритет (вес) любой вершины не меньше ( ≥ ), приоритета потомков
b) дерево является полным двоичным деревом (complete binary tree) – все уровни заполнены, возможно за исключением последнего
Бинарная куча (Binary heap)
4
max-heap
Приоритет любой вершины не меньше (≥),
приоритета потомков
min-heap
Приоритет любой вершины не больше (≤),
приоритета потомков
Реализация бинарной кучи на основе массива
5
2 4
8 7
1
9 3
14 10
16max-heap (10 элементов)
16 14 10 8 7 9 3 2 4 1
Массив H[1..14] приоритетов (ключей):
Корень дерева храниться в ячейке 𝐻[1] – максимальный элемент
Индекс родителя узла i: 𝑃𝑎𝑟𝑒𝑛𝑡 𝑖 = 𝑖/2
Индекс левого дочернего узла: 𝐿𝑒𝑓𝑡 𝑖 = 2𝑖
Индекс правого дочернего узла: 𝑅𝑖𝑔ℎ𝑡 𝑖 = 2𝑖 + 1
𝐻 𝑃𝑎𝑟𝑒𝑛𝑡 𝑖 ≥ 𝐻[𝑖]
Реализация бинарной кучи на основе массива
6
struct heapitem {int priority; /* Приоритет элемента */char *value; /* Данные */
};
struct heap {int maxsize; /* Максимальный размер массива */int nitems; /* Количество элементов в куче */
/* Элементы кучи (хранятся с индекса 1) */struct heapitem *items;
};
struct heap *heap_create(int maxsize) {
struct heap *h;
h = malloc(sizeof(*h));if (h != NULL) {
h->maxsize = maxsize;h->nitems = 0;h->items = malloc(sizeof(struct heapitem) *
(maxsize + 1));if (h->items == NULL) {
free(h);return NULL;
}} return h;
}
Создание пустой кучи
7
TCreate = O(1)
void heap_free(struct heap *h){
free(h->items);free(h);
}
void heap_swap(struct heapitem *a, struct heapitem *b)
{struct heapitem temp;
temp = *a;*a = *b;*b = temp;
}
Удаление кучи
8
Поиск максимального элемента
9
2 4
8 7
1
9 3
14 10
16max-heap (10 элементов)
16 14 10 8 7 9 3 2 4 1
Массив H[1..14] приоритетов (ключей):
Максимальный элемент хранится в корне max-heap
Корень дерева храниться в ячейке 𝐻[1] – максимальный элемент
Индекс родителя узла i: 𝑃𝑎𝑟𝑒𝑛𝑡 𝑖 = 𝑖/2
Индекс левого дочернего узла: 𝐿𝑒𝑓𝑡 𝑖 = 2𝑖
Индекс правого дочернего узла: 𝑅𝑖𝑔ℎ𝑡 𝑖 = 2𝑖 + 1
𝐻 𝑃𝑎𝑟𝑒𝑛𝑡 𝑖 ≥ 𝐻[𝑖]
Поиск максимального элемента
10
struct heapitem heap_max(struct heap *h){
struct heapitem erritem = {-1, NULL};
if (h->nitems > 0) {return h->items[1];
} else {fprintf(stderr,
"heap: Heap is empty.\n");return erritem;
}} TMax = O(1)
Вставка элемента в бинарную кучу
11Вставка элемента с приоритетом 15 [CLRS]
15
15 15
Вставка элемента в бинарную кучу
12
int heap_insert(struct heap *h, int priority, char *value)
{int i;
if (h->nitems >= h->maxsize) {fprintf(stderr,
"heap: Heap overflow.\n");return -1;
}
h->nitems++;h->items[h->nitems].priority = priority;h->items[h->nitems].value = value;
Вставка элемента в бинарную кучу
13
/* Продвигаем элемент вверх */
for (i = h->nitems;
i > 1 && h->items[i].priority >
h->items[i / 2].priority;
i = i / 2)
{
heap_swap(&h->items[i], &h->items[i / 2]);
}
return 0;
} TInsert = O(logn)
Удаление максимального элемента
14
Заменяем корень листом
Восстанавливаем свойства кучи
Удаление максимального элемента
15
struct heapitem heap_removemax(struct heap *h){
int k, n, j;
heap_swap(&h->items[1], &h->items[h->nitems]);
for (k = 1, n = h->nitems - 1; 2 * k <= n; k = j) { j = 2 * k;if (j < n && h->items[j].priority <
h->items[j + 1].priority){
j++;}
if (h->items[k].priority >= h->items[j].priority)
{break;
} heap_swap(&h->items[k], &h->items[j]);
}return h->items[h->nitems--];
}
Удаление максимального элемента
16
TRemoveMax = O(logn)
for (k = 1, n = h->nitems - 1; 2 * k <= n; k = j) { j = 2 * k;if (j < n && h->items[j].priority <
h->items[j + 1].priority){
j++;}
if (h->items[k].priority >= h->items[j].priority)
{break;
} heap_swap(&h->items[k], &h->items[j]);
}return h->items[h->nitems--];
}
Удаление максимального элемента
17
TRemoveMax = O(logn)
Прочитать в [Sedgewick2001, с. 366-368]о функциях fixUp и fixDown
Эти функции составляют основу процедур heap_insert и
heap_removemax
int main()
{
struct heap *h;
struct heapitem item;
h = heap_create(20);
heap_insert(h, 10, “Купить хлеб”);
heap_insert(h, 9, “Заплатить за Интернет”);
heap_insert(h, 15, “Сходить в библиотеку”);
item = heap_removemax(h);
printf("Item: %d\n", item.priority);
heap_free(h);
return 0;
}
Работа с бинарной кучей
18
Сортировка на базе бинарной кучи
19
На основе бинарной кучи можно реализовать алгоритм сортировки с вычислительной сложностью O(nlogn) в худшем случае
Как ?
Сортировка на базе бинарной кучи
20
На основе бинарной кучи можно реализовать алгоритм сортировки с вычислительной сложностью O(nlogn) в худшем случае
Как ?
function HeapSort(v[1:n])
h = CreateBinaryHeap(n)
for i = 1 to n do
HeapInsert(h, v[i], v[i])
end for
for i = 1 to n do
v[i] = HeapRemoveMax(h)
end for
end function
T1 = O(1)
T2 = O(logn)
T3 = O(logn)
Сортировка на базе бинарной кучи
21
На основе бинарной кучи можно реализовать алгоритм сортировки с вычислительной сложностью O(nlogn) в худшем случае
Как ?
function HeapSort(v[1:n])
h = CreateBinaryHeap(n)
for i = 1 to n do
HeapInsert(h, v[i], v[i])
end for
for i = 1 to n do
v[i] = HeapRemoveMax(h)
end for
end function
T1 = O(1)
T2 = O(logn)
T3 = O(logn)
THeapSort = 1 + nlogn + nlogn = O(nlogn)
Построение бинарной кучи
22
Дан неупорядоченный массив A длины n
Требуется построить из его элементов бинарную кучу
Построение бинарной кучи (v1)
23
Дан неупорядоченный массив A длины n
Требуется построить из его элементов бинарную кучу
function BuildHeap(A[1:n])
h = CreateBinaryHeap(n) // O(1)
for i = 1 to n do
HeapInsert(h, A[i], A[i]) // O(logn)
end for
end function TBuildHeap = O(nlogn)
Построение бинарной кучи (v2)
24
Дан неупорядоченный массив A длины n
Требуется построить из его элементов бинарную кучу
function MaxHeapify(A[1:n], i)left = 2 * i // left sub heapright = 2 * i + 1 // right sub heaplargest = iif left <= n and A[left] > A[i] then
largest = leftif right <= n and A[right] > A[largest] then
largest = rightif largest != i then
heap_swap(A[i], A[largest])MaxHeapify(A, largest)
end ifend function
function BuildMaxHeap(A[1:n])h = CreateBinaryHeap(n) // O(1)for i = ⌊n / 2⌋ downto 1 do
MaxHeapify(A, i) // O(h)end function
TBuildHeap = O(n)
Доказательство см. в [CLRS]
Очередь с приоритетом (Priority queue)
25
В таблице приведены трудоемкости операций очереди с приоритетом (в худшем случае, 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)
Домашнее чтение
26
Прочитать в [Sedgewick2001, с. 355] об очередях с приоритетами
Анализа вычислительной сложности построения бинарной кучи (Build-Max-Heap) за время O(n)
[CLRS]
http://en.wikipedia.org/wiki/Binary_heap#Building_a_heap