Быстрая сортировка: различия между версиями

Материал из Олимпиадное программирование в УлГТУ
Перейти к навигации Перейти к поиску
Нет описания правки
Строка 1: Строка 1:
== Алгоритм ==
Выбираем в массиве опорный элемент. За &Theta;(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);
}

Ссылки

Теория:

Демонстрация:

Код:

Задачи: