Skip to content

Built-in Sorting in C++

1. Basic Usage

cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<int> v = {5, 2, 9, 1, 5, 6};

    // Sort in ascending order
    sort(v.begin(), v.end());

    for (int x : v) cout << x << " ";
}

Output:

1 2 5 5 6 9
  • Works on any random-access container (array, vector, deque).
  • Time complexity: O(n log n) on average.

2. Descending Order

cpp
sort(v.begin(), v.end(), greater<int>());

3. Custom Comparators

A comparator is a function (or lambda) that returns true if the first argument should appear before the second.

Example 1: Sort by absolute value

cpp
sort(v.begin(), v.end(), [](int a, int b) {
    return abs(a) < abs(b);
});

Example 2: Sort pairs by first, then second

cpp
vector<pair<int,int>> vp = {{1,3},{1,2},{2,2},{2,1}};

sort(vp.begin(), vp.end(), [](auto &a, auto &b) {
    if (a.first != b.first) return a.first < b.first;
    return a.second < b.second;
});

Output:

(1,2) (1,3) (2,1) (2,2)

4. Rules for Comparators

  • The comparators must impose a strict weak ordering:

    • No contradictions (a < b and b < a cannot both be true).
    • Transitivity : If a < b and b < c, then a < c.
  • Advice : Always use < or > — avoid <= or >= inside comparators.


5. Keeping Original Indices When Sorting

Sometimes you want to sort values but remember where they came from. The trick is to store pairs {index, value}.

cpp
vector<int> a = {50, 20, 40, 10};
int n = a.size();

vector<pair<int,int>> vp; 
for (int i = 0; i < n; i++) {
    vp.push_back({i, a[i]}); // {index, value}
}

// Sort by value
sort(vp.begin(), vp.end(), [](auto &x, auto &y) {
    return x.second < y.second;
});

// Print sorted values with original indices
for (auto [i, val] : vp) {
    cout << "value = " << val << ", original index = " << i << "\n";
}

Output:

value = 10, original index = 3
value = 20, original index = 1
value = 40, original index = 2
value = 50, original index = 0

Tip: Structured Bindings (C++17+)

You can unpack pairs directly in loops.

Instead of:

cpp
for (auto p : vp) {
    int i = p.first;
    int val = p.second;
    cout << i << " " << val << "\n";
}

Write:

cpp
for (auto [i, val] : vp) {
    cout << i << " " << val << "\n";
}

Cleaner, shorter, and easier to read.


6. Sorting Indices Instead of Values

Sort a list of indices according to the array values.

cpp
vector<int> a = {50, 20, 40, 10};
int n = a.size();

vector<int> idx(n);
iota(idx.begin(), idx.end(), 0); // {0,1,2,3}

sort(idx.begin(), idx.end(), [&](int i, int j) {
    return a[i] < a[j];
});

// idx = {3,1,2,0}

7. Sorting with Explicit Tie-Breakers

When multiple keys matter, it is either needed or preferable to make the comparator deterministic (This means that no matter what the original order of the same set of elements is, the output order will always be the same).

cpp
vector<pair<int,int>> vp = {{1,3},{1,2},{2,2},{2,1}};

sort(vp.begin(), vp.end(), [](auto &a, auto &b) {
    if (a.first != b.first) return a.first < b.first;
    return a.second > b.second; // second key descending
});

8. Stable Sort

std::stable_sort preserves the relative order of equal elements. This is useful when you want to sort by multiple criteria in stages or maintain original ordering for equal keys.

Example 1: Simple illustration of stability

cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<pair<int,int>> vp = {{1,200},{2,50},{1,100},{2,75}};

    // Sort by first element using stable_sort
    stable_sort(vp.begin(), vp.end(), [](auto &a, auto &b) {
        return a.first < b.first;
    });

    for (auto [x,y] : vp)
        cout << "(" << x << "," << y << ") ";
}

Output:

(1,200) (1,100) (2,50) (2,75)

✅ The relative order of pairs with the same first element is preserved (200 before 100, 50 before 75).


Example 2: Multi-stage sorting

cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<pair<int,int>> vp = {{1,3},{1,2},{2,2},{2,1}};

    // Step 1: Sort by second element (stable)
    stable_sort(vp.begin(), vp.end(), [](auto &a, auto &b) {
        return a.second < b.second;
    });

    // Step 2: Sort by first element (stable)
    stable_sort(vp.begin(), vp.end(), [](auto &a, auto &b) {
        return a.first < b.first;
    });

    for (auto [x,y] : vp)
        cout << "(" << x << "," << y << ") ";
}

Output:

(1,2) (1,3) (2,1) (2,2)

✅ The first-stage ordering (by second element) is preserved within each group of equal first elements.


Notes:

  • Time complexity: O(n log n)
  • Use stable_sort whenever you need multi-level sorting without writing a complex comparator.