Частичные сортировки
Требуется узнать первые k элементов в отсортированном массиве.
Варианты: 1. Отсортировать весь массив полностью O(nlogn) 2. Неполная HeapSort: T(k,n)=T(makeheap)+k⋅T(extractmin)=O(n)+k⋅O(logn). Если k=o(nlogn)⇒T(k,n)=O(n). Быстрее (ассимптотически) сделать нельзя. 3. Запустить QuickSort только на тех левых половинах, длина которых меньше k. Время работы O(n+klogk) в среднем (доказательство ниже).
Порядковые статистики
k-я порядковая статистика для массива -- это элемент, который будет стоять на k-ом месте в отсортированном массиве. Медиана -- это ⌈n2⌉ порядковая статистика
Randomized selection
def randomized_selection(a, r, l, k):
px = rand(l, r)
m_l, m_r = partition3(a, l, r, px) # берем partition, который учитывает одинаковые элементы
if m_l - l > k:
return randomized_selection(a, l, m_l, k)
elif m_r - i > k:
return a[m_l]
else:
return randomized_selection(a, m_r, r, k - m_r)
Оценка: 1. Худший случай: T(n)≤T(n−1)+O(n)=O(n2) 2. Средний случай: E(#partition: получим "хорошее разбиение")=2 E(T(n))≤E(T(3/4n))+E(#...)⋅O(n)=E(T(3/4n))+O(n)=O(n)
Сравнение с частичной сортировкой: T(PartialQuickSort(n, k))≤T(RandomizedSelection(n, k))+T(QuickSort(k))=O(n)+O(klogk)
"Медиана медиан" (Блюм-Флойд-Пратт-Равест-Таржан)
- Разбиваем массив на группы по пять элементов
- Сортируем группы
- Строим массив
b
, состоящий из медиан этих групп - Вызываемся рекурсивно на
b
и получаем медиануm
- Используем
m
вpartition
и вызываемся рекурсивно
def mm(a, l, r, k):
if l - r == 1:
return a[l]
sort_by_5(a, l, r)
b = medians_by_5(a, l, r)
m = mm(b, 0, len(b), len(b) / 2)
px = a[m]
i = partition(a, l, r, px)
if i == k:
return a[i]
if i > k:
return mm(a, l, i, k)
else:
return mm(a, i, r, k - d)
Оценка:
T(n)≤T(n5)+T(n⋅710)+O(n) Хотим доказать T(n)=O(n)≤C⋅n+d C⋅n+d≤C⋅n5+d+C⋅7n10+d+αn+β
- d=β
- C⋅(1−15−710)=0.1C=α⇒C=10α
Следствие: QuickSort можно реализовать за O(nlogn) в худшем случае.