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

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

Embed Size (px)

Citation preview

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

Лекция 7:

Очереди с приоритетами

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

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

Сибирский государственный университет

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

http://www.mkurnosov.net

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

Контроль

2

1. Как реализовать хеш-функцию для

вещественных чисел?

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

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

Слон 3

Кит 1

Лев 15

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

3

Очередь с приоритетом (Priority queue) – очередь, в которой

элементы имеют приоритет (вес)

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

o Insert(key, value) – добавление элемента в очередь

o DeleteMin/DeleteMax – удаляет из очереди элемент

с мин./макс. ключом

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

o DecreaseKey – изменяет значение ключа элемента

o Merge(q1, q2) – сливает две очереди в одну

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

Двоичная куча (Binary Heap)

4

Двоичная куча (пирамида, сортирующее дерево,

binary heap) – это двоичное дерево, удовлетворяющее

следующим условиям:

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

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

b) дерево является полным двоичным деревом

(complete binary tree) – все уровни

заполнены, возможно

за исключением последнего

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

Двоичная куча (Binary heap)

5

max-heap

Приоритет любой вершины

не меньше (≥),

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

min-heap

Приоритет любой вершины

не больше (≤),

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

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

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

6

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]:

Корень дерева храниться вячейке H[1] – максимальный элемент

Индекс родителя узла i: Parent(i) = /2

Индекс левого дочернего узла: Left(i) = 2i

Индекс правого дочернего узла: Right(i) = 2i + 1

H[Parent(i)] ≥ H[i]

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

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

7

struct heapitem

int priority; /* Приоритет элемента */

char *value; /* Данные */

;

struct heap

int maxsize; /* Максимальный размер массива */

int nitems; /* Количество элементов в куче */

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

struct heapitem *items;

;

Page 8: Лекция 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;

Создание пустой кучи

8

TCreate

= O(1)

Page 9: Лекция 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;

Удаление кучи

9

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

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

10

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]:

Корень дерева храниться вячейке H[1] – максимальный элемент

Индекс родителя узла i: Parent(i) = /2

Индекс левого дочернего узла: Left(i) = 2i

Индекс правого дочернего узла: Right(i) = 2i + 1

H[Parent(i)] ≥ H[i]

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

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

11

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;

T

Max= O(1)

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

Вставка элемента в двоичную кучу

12Вставка элемента с приоритетом 15 (Cormen2002)

15

15 15

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

Вставка элемента в двоичную кучу

13

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 14: Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)

Вставка элемента в двоичную кучу

14

/* Продвигаем элемент вверх */

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 15: Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)

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

15

Элемент 2 (приоритет 4)

нарушил структуру кучи:

4 < 14 и 4 < 7, 4 < 8

(Cormen2002)

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

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

16

struct heapitem heap_removemax(struct heap *h)

int k, n, j;

heap_swap(&h->items[1],

&h->items[h->nitems]);

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--];

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

17TRemoveMax

= O(logn)

Page 18: Лекция 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--];

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

18

Прочитать в Sedgewick2001, с. 366-368

о функциях fixUp и fixDown

Эти функции составляют основу процедур

heap_insert и heap_removemax

Page 19: Лекция 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;

Работа с двоичной кучей

19

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(n)

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(n)

T2 = O(logn)

T3 = O(logn)

T = T1 + nT2 + nT3 =

= n + nlogn + nlogn

= O(nlogn)

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

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

22

В таблице приведены трудоемкости операций очереди

с приоритетом (в худшем случае, worst case)

Символом ‘*’ отмечена амортизированная сложность операции

ОперацияBinary

heap

Binomial

heap

Fibonacci

heap

Pairing

heap

Brodal

heap

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)