Grade 10 · Divide and conquerCitește în română

Quick sort

Original: Sortarea rapidă (Quick Sort)

O(n log n)C++1768 lines2 examples

The idea

We pick a pivot (here the middle element) and rearrange the portion so that values <= pivot end up on the left and values >= pivot on the right: index i advances while v[i] < pivot, j goes down while v[j] > pivot, then v[i] and v[j] are swapped. When i and j cross, we sort the two pieces recursively. Unlike merge sort, the work is done BEFORE the recursive calls and no helper array is needed.

Original description (Romanian)

Alegem un pivot (aici elementul din mijloc) și rearanjăm porțiunea astfel încât în stânga să ajungă valori <= pivot, iar în dreapta valori >= pivot: indicele i înaintează cât timp v[i] < pivot, j coboară cât timp v[j] > pivot, apoi v[i] și v[j] se interschimbă. Când i și j se încrucișează, sortăm recursiv cele două bucăți. Spre deosebire de interclasare, munca se face ÎNAINTE de autoapeluri și nu e nevoie de vector auxiliar.

Complexity
O(n log n) on average, O(n * n) in the worst case
Grade
Grade 10 (Clasa a X-a)

Examples

Example 1

Input

8
5 2 9 1 5 6 3 8

Expected output

1 2 3 5 5 6 8 9
Example 2

Input

5
7 7 7 1 7

Expected output

1 7 7 7 7

The code

Comments are in Romanian, as in the original collection. Edit freely: you can reset at any time.

sortare-rapida.cpp
/*
 * Titlu: Sortarea rapidă (Quick Sort)
 * Clasa: 10
 * Capitol: Divide et impera
 * Descriere: Alegem un pivot (aici elementul din mijloc) și rearanjăm porțiunea
 *            astfel încât în stânga să ajungă valori <= pivot, iar în dreapta valori
 *            >= pivot: indicele i înaintează cât timp v[i] < pivot, j coboară cât
 *            timp v[j] > pivot, apoi v[i] și v[j] se interschimbă. Când i și j se
 *            încrucișează, sortăm recursiv cele două bucăți. Spre deosebire de
 *            interclasare, munca se face ÎNAINTE de autoapeluri și nu e nevoie de
 *            vector auxiliar.
 * Complexitate: O(n log n) în medie, O(n * n) în cazul cel mai nefavorabil
 *
 * Exemplu
 * Intrare:
 * 8
 * 5 2 9 1 5 6 3 8
 * Ieșire: 1 2 3 5 5 6 8 9
 *
 * Exemplu
 * Intrare:
 * 5
 * 7 7 7 1 7
 * Ieșire: 1 7 7 7 7
 */
#include <iostream>
using namespace std;

int v[100000];

void sortareRapida(int st, int dr)
{
    if (st >= dr)
        return;
    int pivot = v[(st + dr) / 2];
    int i = st, j = dr;
    while (i <= j)
    {
        while (v[i] < pivot)
            i++;
        while (v[j] > pivot)
            j--;
        if (i <= j)
        {
            int t = v[i];
            v[i] = v[j];
            v[j] = t;
            i++;
            j--;
        }
    }
    sortareRapida(st, j);
    sortareRapida(i, dr);
}

int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> v[i];
    sortareRapida(0, n - 1);
    for (int i = 0; i < n; i++)
        cout << v[i] << ' ';
    cout << '\n';
    return 0;
}

Runs on a real g++ (C++17, -O2) through Compiler Explorer. Keep runs short; there's a time limit.