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

Merge sort

Original: Sortarea prin interclasare (Merge Sort)

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

The idea

We split the array into two halves, sort each half recursively, then merge them: we always compare the first remaining elements of the two halves and move the smaller one into a helper array. At the end we copy the result back. A portion with one element is already sorted. We use <= when comparing, so the sort is stable (equal elements keep their order).

Original description (Romanian)

Împărțim vectorul în două jumătăți, sortăm recursiv fiecare jumătate, apoi le interclasăm: comparăm mereu primele elemente rămase din cele două jumătăți și îl mutăm pe cel mai mic într-un vector auxiliar. La final copiem rezultatul înapoi. O porțiune cu un element este deja sortată. Folosim <= la comparare, deci sortarea este stabilă (elementele egale își păstrează ordinea).

Complexity
O(n log n) in every case, with O(n) extra memory
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

3
3 2 1

Expected output

1 2 3

The code

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

sortare-prin-interclasare.cpp
/*
 * Titlu: Sortarea prin interclasare (Merge Sort)
 * Clasa: 10
 * Capitol: Divide et impera
 * Descriere: Împărțim vectorul în două jumătăți, sortăm recursiv fiecare jumătate,
 *            apoi le interclasăm: comparăm mereu primele elemente rămase din cele
 *            două jumătăți și îl mutăm pe cel mai mic într-un vector auxiliar.
 *            La final copiem rezultatul înapoi. O porțiune cu un element este deja
 *            sortată. Folosim <= la comparare, deci sortarea este stabilă
 *            (elementele egale își păstrează ordinea).
 * Complexitate: O(n log n) în orice caz, cu memorie suplimentară O(n)
 *
 * Exemplu
 * Intrare:
 * 8
 * 5 2 9 1 5 6 3 8
 * Ieșire: 1 2 3 5 5 6 8 9
 *
 * Exemplu
 * Intrare:
 * 3
 * 3 2 1
 * Ieșire: 1 2 3
 */
#include <iostream>
using namespace std;

int v[100000], aux[100000];

void interclaseaza(int st, int m, int dr)
{
    int i = st, j = m + 1, k = 0;
    while (i <= m && j <= dr)
    {
        if (v[i] <= v[j])
            aux[k++] = v[i++];
        else
            aux[k++] = v[j++];
    }
    while (i <= m)
        aux[k++] = v[i++];
    while (j <= dr)
        aux[k++] = v[j++];
    for (int t = 0; t < k; t++)
        v[st + t] = aux[t];
}

void sorteaza(int st, int dr)
{
    if (st >= dr)
        return;
    int m = (st + dr) / 2;
    sorteaza(st, m);
    sorteaza(m + 1, dr);
    interclaseaza(st, m, dr);
}

int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> v[i];
    sorteaza(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.