Upload
mikhail-kurnosov
View
3.127
Download
0
Embed Size (px)
Citation preview
Лекция 7:
Очереди с приоритетами
Курносов Михаил Георгиевич
к.т.н. доцент Кафедры вычислительных систем
Сибирский государственный университет
телекоммуникаций и информатики
http://www.mkurnosov.net
Контроль
2
1. Как реализовать хеш-функцию для
вещественных чисел?
Значение (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) – сливает две очереди в одну
Двоичная куча (Binary Heap)
4
Двоичная куча (пирамида, сортирующее дерево,
binary heap) – это двоичное дерево, удовлетворяющее
следующим условиям:
a) приоритет (вес) любой вершины не меньше ( ≥ ),
приоритета потомков
b) дерево является полным двоичным деревом
(complete binary tree) – все уровни
заполнены, возможно
за исключением последнего
Двоичная куча (Binary heap)
5
max-heap
Приоритет любой вершины
не меньше (≥),
приоритета потомков
min-heap
Приоритет любой вершины
не больше (≤),
приоритета потомков
Реализация двоичной кучи на основе массива
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]
Реализация двоичной кучи на основе массива
7
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;
Создание пустой кучи
8
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;
Удаление кучи
9
Поиск максимального элемента
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]
Поиск максимального элемента
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)
Вставка элемента в двоичную кучу
12Вставка элемента с приоритетом 15 (Cormen2002)
15
15 15
Вставка элемента в двоичную кучу
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;
Вставка элемента в двоичную кучу
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)
Удаление максимального элемента
15
Элемент 2 (приоритет 4)
нарушил структуру кучи:
4 < 14 и 4 < 7, 4 < 8
(Cormen2002)
Удаление максимального элемента
16
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--];
Удаление максимального элемента
17TRemoveMax
= 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--];
Удаление максимального элемента
18
Прочитать в 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;
Работа с двоичной кучей
19
Сортировка на базе двоичной кучи
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)
Сортировка на базе двоичной кучи
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)
Очередь с приоритетом (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)