Куча

Куча — корневое дерево со свойством кучи. Свойство min кучи: для любой вершины $\forall v$: $key(v) \geqslant key(parent(v))$; значение в каждом узле не меньше значения в родителе.

Двоичная куча — полное двоичное дерево (все, кроме последнего, слои заняты) со свойством кучи. Можно реализовать на массиве.

left(v)   = 2v
right(v)  = 2v + 1
parent(v) = v div 2
Индексация с единицы, v = 1..n

Высота двоичной кучи = $\log_2(n) \pm 1$ (????????)

Операции над кучей

K-ичная куча

Применение кучи

Линейные сортировки

Нижняя оценка на сортировки сравнениями: сортировка $n$ элементов требует $\Omega(n \log n)$ операций. Линейные сортировки работают быстрее, если про них известно что-то еще, кроме операции сравнения.

Counting sort (сортировка подсчетом)

Если в массиве хранятся простые элементы из небольшого множества (числа от $1$ до $100$, char). $n$ — размер массива, $m$ — максимальное значение элементов в массиве.

Алгоритм: считаем, сколько раз каждый элемент встречается, потом по массиву с подсчитанными элементами восстанавливаем отсортированный массив.

Время: $O(n+m)$, память: $O(m)$. Сортировка стабильная.

Если помимо ключей в массиве интересуют еще и связанные значения, то в вспомогательном массиве храним индексы элементов в отсортированном массиве.

def counting_sort(a, m):
    b = [0 for i in range(m)]
    # подсчет
    for x in a:
        b[a[i]] += 1
    # массив индексов
    c = [0 for i in range(m)]
    for i in range(2, len(b)):
        c[i] = c[i - 1] + b[i - 1]
    # восстановление ответа
    res = [o for i in range(n)]
    for i in range(n):
        res[c[a[i]]] = a[i]
        c[a[i]] += 1
    return res

Radix sort (поразрядная сортировка)

Элементы, которые мы сортируем сами по себе последовательности элементов (строки, длинные числа).

Сначала сортируем по последнему разряду сортировкой подсчетом. Потом по предпоследнему. И так далее. (Сначала единицы, потом десятки, потом сотни...)

Если $n$ — число элементов, а $d$ — число разрядов, то:

Время: $O(n+d)$, память: $O(d)$. Сортировка стабильная.

Bucket sort

Допустим есть вещественные числа, равномерно распределенные по какому-то отрезку. $n$ чисел, $n$ bucket'ов (разбить исходный отрезок на $n$ частей). Если в один bucket попадает больше одной точки, то сортируем его любой сортировкой (вероятность таких случаев крайне мала). Выписываем все элементы из всех bucket'ов.

Если входные данные хорошие, то работает за $O(n)$.