26
Лекция 7 Бинарные кучи (пирамиды) Курносов Михаил Георгиевич к.т.н. доцент Кафедры вычислительных систем Сибирский государственный университет телекоммуникаций и информатики http://www.mkurnosov.net/teaching

Лекция 7: Бинарные кучи (пирамиды)

Embed Size (px)

Citation preview

Page 1: Лекция 7: Бинарные кучи (пирамиды)

Лекция 7Бинарные кучи (пирамиды)

Курносов Михаил Георгиевич

к.т.н. доцент Кафедры вычислительных систем Сибирский государственный университет

телекоммуникаций и информатики

http://www.mkurnosov.net/teaching

Page 2: Лекция 7: Бинарные кучи (пирамиды)

2

Значение (Value) Приоритет (Priority)

Слон 3

Кит 1

Лев 15

Очередь с приоритетом (Priority queue)

Очередь с приоритетом (Priority queue) –очередь, в которой элементы имеют приоритет (вес); первым извлекается элемент с большим/меньшим приоритетом

Поддерживаемые операции:

Insert – добавление элемента в очередь

DeleteMin/DeleteMax – удаляет из очереди элемент с мин./макс. приоритетом

Min/Max – возвращает элемент с мин./макс. приоритетом

DecreaseKey – изменяет значение приоритета элемента

Merge – сливает две очереди в одну

Page 3: Лекция 7: Бинарные кучи (пирамиды)

Бинарная куча (Binary heap)

3

Бинарная куча (пирамида, сортирующее дерево, binary heap) – это двоичное дерево, удовлетворяющее следующим условиям:

a) приоритет (вес) любой вершины не меньше ( ≥ ), приоритета потомков

b) дерево является полным двоичным деревом (complete binary tree) – все уровни заполнены, возможно за исключением последнего

Page 4: Лекция 7: Бинарные кучи (пирамиды)

Бинарная куча (Binary heap)

4

max-heap

Приоритет любой вершины не меньше (≥),

приоритета потомков

min-heap

Приоритет любой вершины не больше (≤),

приоритета потомков

Page 5: Лекция 7: Бинарные кучи (пирамиды)

Реализация бинарной кучи на основе массива

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

𝐻 𝑃𝑎𝑟𝑒𝑛𝑡 𝑖 ≥ 𝐻[𝑖]

Page 6: Лекция 7: Бинарные кучи (пирамиды)

Реализация бинарной кучи на основе массива

6

struct heapitem {int priority; /* Приоритет элемента */char *value; /* Данные */

};

struct heap {int maxsize; /* Максимальный размер массива */int nitems; /* Количество элементов в куче */

/* Элементы кучи (хранятся с индекса 1) */struct heapitem *items;

};

Page 7: Лекция 7: Бинарные кучи (пирамиды)

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)

Page 8: Лекция 7: Бинарные кучи (пирамиды)

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

Page 9: Лекция 7: Бинарные кучи (пирамиды)

Поиск максимального элемента

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

𝐻 𝑃𝑎𝑟𝑒𝑛𝑡 𝑖 ≥ 𝐻[𝑖]

Page 10: Лекция 7: Бинарные кучи (пирамиды)

Поиск максимального элемента

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)

Page 11: Лекция 7: Бинарные кучи (пирамиды)

Вставка элемента в бинарную кучу

11Вставка элемента с приоритетом 15 [CLRS]

15

15 15

Page 12: Лекция 7: Бинарные кучи (пирамиды)

Вставка элемента в бинарную кучу

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;

Page 13: Лекция 7: Бинарные кучи (пирамиды)

Вставка элемента в бинарную кучу

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)

Page 14: Лекция 7: Бинарные кучи (пирамиды)

Удаление максимального элемента

14

Заменяем корень листом

Восстанавливаем свойства кучи

Page 15: Лекция 7: Бинарные кучи (пирамиды)

Удаление максимального элемента

15

struct heapitem heap_removemax(struct heap *h){

int k, n, j;

heap_swap(&h->items[1], &h->items[h->nitems]);

Page 16: Лекция 7: Бинарные кучи (пирамиды)

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)

Page 17: Лекция 7: Бинарные кучи (пирамиды)

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

Page 18: Лекция 7: Бинарные кучи (пирамиды)

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

Page 19: Лекция 7: Бинарные кучи (пирамиды)

Сортировка на базе бинарной кучи

19

На основе бинарной кучи можно реализовать алгоритм сортировки с вычислительной сложностью O(nlogn) в худшем случае

Как ?

Page 20: Лекция 7: Бинарные кучи (пирамиды)

Сортировка на базе бинарной кучи

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)

Page 21: Лекция 7: Бинарные кучи (пирамиды)

Сортировка на базе бинарной кучи

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)

Page 22: Лекция 7: Бинарные кучи (пирамиды)

Построение бинарной кучи

22

Дан неупорядоченный массив A длины n

Требуется построить из его элементов бинарную кучу

Page 23: Лекция 7: Бинарные кучи (пирамиды)

Построение бинарной кучи (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)

Page 24: Лекция 7: Бинарные кучи (пирамиды)

Построение бинарной кучи (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]

Page 25: Лекция 7: Бинарные кучи (пирамиды)

Очередь с приоритетом (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)

Page 26: Лекция 7: Бинарные кучи (пирамиды)

Домашнее чтение

26

Прочитать в [Sedgewick2001, с. 355] об очередях с приоритетами

Анализа вычислительной сложности построения бинарной кучи (Build-Max-Heap) за время O(n)

[CLRS]

http://en.wikipedia.org/wiki/Binary_heap#Building_a_heap