Быстрая сортировка: различия между версиями
Ctrlalt (обсуждение | вклад) (→Ссылки) |
Ctrlalt (обсуждение | вклад) Нет описания правки |
||
Строка 1: | Строка 1: | ||
== Алгоритм == | |||
Выбираем в массиве опорный элемент. За Θ(N) делим массив на части: (<= опорного), (опорный), (>= опорного). Левую и правую части сортируем рекурсивно. | |||
В лучшем случае, если опорный элемент будет делить массив примерно пополам, получим сложность O(NlogN), как у сортировки слиянием. | |||
С другой стороны, если опорный элемент каждый раз выбирать неудачно (близко к минимуму или максимуму), то одна из половин будет почти пустой, а сложность деградирует до O(N<sup>2</sup>). | |||
Если в качестве опорного выбирать любой фиксированный элемент, всегда можно составить контртест, на котором время работы будет квадратичным. Чтобы избежать худшего случая, требуется в качестве опорного выбирать случайный элемент в рассматриваемом диапазоне. Можно показать, что ожидаемая сложность при этом составит O(NlogN); константа у быстрой сортировки, как правило, меньше, чем у других сортировок с подобной асимптотической сложностью. | |||
void quickSort(vector<int> &a, int l, int r) { | |||
if (l >= r) | |||
return; | |||
uniform_int_distribution<int> distribution(l, r); | |||
swap(a[l], a[distribution(generator)]); | |||
int i = l + 1, j = r; | |||
while (1) { | |||
while (i <= r && a[i] < a[l]) | |||
i++; | |||
while (j > l && a[j] > a[l]) | |||
j--; | |||
if (i >= j) | |||
break; | |||
swap(a[i++], a[j--]); | |||
} | |||
swap(a[l], a[j]); | |||
quickSort(a, l, j - 1); | |||
quickSort(a, j + 1, r); | |||
} | |||
== K-я порядковая статистика за O(N) == | |||
minstd_rand generator; | |||
{{Changed|int}} quickSort(vector<int> &a, int l, int r, {{Changed|1=int k}}) { | |||
uniform_int_distribution<int> distribution(l, r); | |||
swap(a[l], a[distribution(generator)]); | |||
int i = l + 1, j = r; | |||
while (1) { | |||
while (i <= r && a[i] < a[l]) | |||
i++; | |||
while (j > l && a[j] > a[l]) | |||
j--; | |||
if (i >= j) | |||
break; | |||
swap(a[i++], a[j--]); | |||
} | |||
swap(a[l], a[j]); | |||
{{Changed|1=if (k < j)}} | |||
{{Changed|1=return quickSort(a, l, j - 1, k);}} | |||
{{Changed|1=if (k == j)}} | |||
{{Changed|1=return a[j];}} | |||
{{Changed|1=else}} | |||
{{Changed|1=return quickSort(a, j + 1, r, k);}} | |||
} | |||
== Ссылки == | == Ссылки == | ||
Теория: | Теория: |
Версия от 10:10, 9 ноября 2021
Алгоритм
Выбираем в массиве опорный элемент. За Θ(N) делим массив на части: (<= опорного), (опорный), (>= опорного). Левую и правую части сортируем рекурсивно.
В лучшем случае, если опорный элемент будет делить массив примерно пополам, получим сложность O(NlogN), как у сортировки слиянием.
С другой стороны, если опорный элемент каждый раз выбирать неудачно (близко к минимуму или максимуму), то одна из половин будет почти пустой, а сложность деградирует до O(N2).
Если в качестве опорного выбирать любой фиксированный элемент, всегда можно составить контртест, на котором время работы будет квадратичным. Чтобы избежать худшего случая, требуется в качестве опорного выбирать случайный элемент в рассматриваемом диапазоне. Можно показать, что ожидаемая сложность при этом составит O(NlogN); константа у быстрой сортировки, как правило, меньше, чем у других сортировок с подобной асимптотической сложностью.
void quickSort(vector<int> &a, int l, int r) { if (l >= r) return; uniform_int_distribution<int> distribution(l, r); swap(a[l], a[distribution(generator)]); int i = l + 1, j = r; while (1) { while (i <= r && a[i] < a[l]) i++; while (j > l && a[j] > a[l]) j--; if (i >= j) break; swap(a[i++], a[j--]); } swap(a[l], a[j]); quickSort(a, l, j - 1); quickSort(a, j + 1, r); }
K-я порядковая статистика за O(N)
minstd_rand generator;
int quickSort(vector<int> &a, int l, int r, int k) { uniform_int_distribution<int> distribution(l, r); swap(a[l], a[distribution(generator)]); int i = l + 1, j = r; while (1) { while (i <= r && a[i] < a[l]) i++; while (j > l && a[j] > a[l]) j--; if (i >= j) break; swap(a[i++], a[j--]); } swap(a[l], a[j]); if (k < j) return quickSort(a, l, j - 1, k); if (k == j) return a[j]; else return quickSort(a, j + 1, r, k); }
Ссылки
Теория:
- neerc.ifmo.ru/wiki — Быстрая сортировка
- neerc.ifmo.ru/wiki — Поиск k-ой порядковой статистики
- brestprog.neocities.org — Сортировка
- algorithmica.org — Быстрая сортировка (см. последнюю часть конспекта)
- algs4.cs.princeton.edu/lectures — 2.3 Quicksort
- Brilliant.org — Quicksort
Демонстрация:
Код:
- CodeLibrary — Sorting algorithms
- CodeLibrary — Kth order statistic in O(N) on average
- Algos — Quick sort with random pivot element
- algs4.cs.princeton.edu/code — quicksort, quicksort with 3-way partitioning, optimized quicksort
Задачи: