std::ranges::partial_sort(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

okay bestie, this is the std::ranges::partial_sort(3) page from the C++ Standard Library manual. It’s giving β€œsort just a lil bit of your range” energy, and honestly? iconic. πŸŽ€

✨ NAME ✨

std::ranges::partial_sort β€” yes bestie, the name is literally std::ranges::partial_sort. Main character algorithm, no notes. πŸ’…

πŸ’… Synopsis πŸ’…

Defined in header <algorithm>. Call signature time, and yes you’re gonna read it because it’s important, bestie:

template< std::random_access_iterator I, std::sentinel_for<I> S,
          class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>
(1) (since C++20)
constexpr I
    partial_sort( I first, I middle, S last, Comp comp = {}, Proj proj = {} );
template< ranges::random_access_range R,
          class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
constexpr ranges::borrowed_iterator_t<R>
(2) (since C++20)
    partial_sort( R&& r, ranges::iterator_t<R> middle, Comp comp = {},
                  Proj proj = {} );
  1. Rearranges elements such that the range [first, middle) contains the sorted middle - first smallest elements in the range [first, last). The order of equal elements is not guaranteed to be preserved. The order of the remaining elements in the range [middle, last) is unspecified. The elements are compared using the given binary comparison function comp and projected using proj function object.
  2. Same as (1), but uses r as the range, as if using ranges::begin(r) as first and ranges::end(r) as last.

The function-like entities described on this page are niebloids, that is:

  • Explicit template argument lists cannot be specified when calling any of them.
  • None of them are visible to argument-dependent lookup.
  • When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.

In practice, they may be implemented as function objects, or with special compiler extensions.

🌸 Parameters 🌸

  • first, last β€” iterator-sentinel defining the range to sort.
  • r β€” the range to sort.
  • middle β€” the iterator defining the last element to be sorted.
  • comp β€” comparator to apply to the projected elements.
  • proj β€” projection to apply to the elements.

πŸ¦‹ Return value πŸ¦‹

An iterator equal to last. periodt. πŸ’–

πŸ”₯ Complexity πŸ”₯

The page writes the math as \(\scriptsize \mathcal{O}(N\cdot\log{(M)})\)π“ž(NΒ·log(M)) β€” so, in human bestie terms, that’s O(NΒ·log(M)) comparisons and twice as many projections, where N is ranges::distance(first, last) and M is ranges::distance(first, middle).

🧚 Possible implementation 🧚

okay this is the whole vibe, exactness and all:

struct partial_sort_fn {
    template<std::random_access_iterator I, std::sentinel_for<I> S,
             class Comp = ranges::less, class Proj = std::identity>
    requires std::sortable<I, Comp, Proj>
    constexpr I
        operator()(I first, I middle, S last, Comp comp = {}, Proj proj = {}) const
    {
        if (first == middle)
            return ranges::next(first, last);
        ranges::make_heap(first, middle, comp, proj);
        auto it {middle};
        for (; it != last; ++it)
        {
            if (std::invoke(comp, std::invoke(proj, *it), std::invoke(proj, *first)))
            {
                ranges::pop_heap(first, middle, comp, proj);
                ranges::iter_swap(middle - 1, it);
                ranges::push_heap(first, middle, comp, proj);
            }
        }
        ranges::sort_heap(first, middle, comp, proj);
        return it;
    }

    template<ranges::random_access_range R, class Comp = ranges::less,
             class Proj = std::identity>
    requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
    constexpr ranges::borrowed_iterator_t<R>
        operator()(R&& r, ranges::iterator_t<R> middle, Comp comp = {}, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), std::move(middle), ranges::end(r),
                       std::move(comp), std::move(proj));
    } };

inline constexpr partial_sort_fn partial_sort {};

πŸ‘‘ Example πŸ‘‘

// Run this code

#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
#include <vector>

void print(const auto& v)
{
    for (const char e : v)
        std::cout << e << ' ';
    std::cout << '\n';
}

void underscore(int n)
{
    while (n-- > 0)
        std::cout << "^ ";
    std::cout << '\n';
}

int main()
{
    static_assert('A' < 'a');
    std::vector<char> v {'x', 'P', 'y', 'C', 'z', 'w', 'P', 'o'};
    print(v);
    const int m {3};
    std::ranges::partial_sort(v, v.begin() + m);
    print(v), underscore(m);

    static_assert('1' < 'a');
    std::string s {"3a1b41c5"};
    print(s);
    std::ranges::partial_sort(s.begin(), s.begin() + m, s.end(),
                              std::greater {});
    print(s), underscore(m);
}

⭐ Output ⭐

        x P y C z w P o
        C P P y z x w o
        ^ ^ ^
        3 a 1 b 4 1 c 5
        c b a 1 3 1 4 5
        ^ ^ ^

🌈 See also 🌈

  • ranges::partial_sort_copy β€” copies and partially sorts a range of elements. (C++20) (niebloid)
  • ranges::sort β€” sorts a range into ascending order. (C++20) (niebloid)
  • ranges::stable_sort β€” sorts a range of elements while preserving order between equal elements. (C++20) (niebloid)
  • ranges::nth_element β€” partially sorts the given range making sure that it is partitioned by the given element. (C++20) (niebloid)
  • ranges::make_heap β€” creates a max heap out of a range of elements. (C++20) (niebloid)
  • ranges::pop_heap β€” removes the largest element from a max heap. (C++20) (niebloid)
  • ranges::push_heap β€” adds an element to a max heap. (C++20) (niebloid)
  • ranges::sort_heap β€” turns a max heap into a range of elements sorted in ascending order. (C++20) (niebloid)
  • partial_sort β€” sorts the first N elements of a range. (function template)

cute sign-off bestie: source/version/date is http://cppreference.com, 2024.06.10, std::ranges::partial_sort(3). That’s the whole page β€” go sort your little range and slay. πŸ’–βœ¨

πŸ“¦ where this page comes from