Beginner's Guide
    First Steps
    Input & Output
    Custom Types – Part 1
    Diagnostics
    Standard Library – Part 1
    Function Objects
    Standard Library – Part 2
    Code Organization
    Custom Types – Part 2
    Generic Programming
    Memory Management
    Software Design Basics

    Standard Library Sequence Reordering Algorithms Sequence Reordering Algorithms Reorder

    Shift Elements Shift

    reverse / reverse_copy reverse_copy reverse

    std::vector<int> v {0,1,2,4,6,8,9,3,5};
    // reverse subrange (as shown in image):
    reverse(begin(v)+2, begin(v)+7);  
    for(int x : v) { cout << x << ' '; }  // 0 1 9 8 6 4 2 3 5
    // reverse entire vector:
    reverse(begin(v), end(v));  
    for(int x : v) { cout << x << ' '; }  // 5 3 2 4 6 8 9 1 0
    std::vector<int> v {2,4,6,8,9};
    std::ranges::reverse(v);
    for(int x : v) { cout << x << ' '; }  // 9 8 6 4 2

    the output must be able to recieve as many elements as there are in the input range

    std::vector<int> in {0,1,2,4,6,8,9,3,5};
    std::vector<int> out; 
    out.resize(5);
    reverse_copy(begin(in)+2, begin(in)+7, begin(out));
    for(int x : out) { cout << x << ' '; }  // 9 8 6 4 2

    the output must be able to recieve as many elements as there are in the input range

    std::vector<int> in {2,4,6,8,9};
    std::vector<int> out; 
    out.resize(in.size());
    std::ranges::reverse_copy(in, begin(out));
    for(int x : out) { cout << x <<' '; }  // 9 8 6 4 2

    rotate / rotate_copy rotate rotate

    performs a cyclic left rotation: all elements from begin to one before new_fist are moved behind the last element

    std::vector<int> v {1,2,3,4,5,6,7};
    auto i = rotate(begin(v), begin(v)+2, end(v));  
    for(int x : v) { cout << x <<' '; }  // 3 4 5 6 7 1 2
    // returned iterator refers to old first:
    auto const value = *i;  // 1
    auto const index = distance(begin(v), i);  // 5
    std::vector<int> v {1,2,3,4,5,6,7};
    auto sub = std::ranges::rotate(v, begin(v)+4);  
    for(int x : v)   { cout << x <<' '; }  // 5 6 7 1 2 3 4
    for(int x : sub) { cout << x <<' '; }  // 1 2 3 4

    the output must be able to recieve as many elements as there are in the input range

    std::vector<int> in {1,2,3,4,5,6,7};
    std::vector<int> out; 
    out.resize(in.size());
    rotate_copy(begin(in), begin(in)+2,             end(in), begin(out));  
    for(int x : out) { cout << x <<' '; }  // 3 4 5 6 7 1 2

    the output must be able to recieve as many elements as there are in the input range

    std::vector<int> in {1,2,3,4,5,6,7};
    std::vector<int> out; 
    out.resize(in.size());
    std::ranges::rotate_copy(in, begin(in)+4, out);  
    for(int x : out) { cout << x <<' '; }  // 5 6 7 1 2 3 4

    shift_left / shift_right shift_left/ right shift_left/right

    std::vector<int> v {1,2,3,4,5,6,7,8};
    int const by = 3;
    shift_left(begin(v), end(v), by);  
    for(int x : v) { cout << x <<' '; }  // 4 5 6 7 8 6 7 8
    std::vector<int> v {1,2,3,4,5,6,7,8};
    int const by = 3;
    shift_right(begin(v), end(v), by);  
    for(int x : v) { cout << x <<' '; }  // 1 2 3 1 2 3 4 5

    shuffle shuffle

    #include <random>
    // 32 bit mersenne twister engine
    auto rgen = std::mt19937{};
    std::vector<int> v {0,1,2,3,4,5,6,7,8};
    shuffle(begin(v)+2, begin(v)+7, rgen);  
    for(int x : v) { cout << x <<' '; }  // 0 1 … 7 8
    #include <random>
    // 32 bit mersenne twister engine
    auto rgen = std::mt19937{};
    std::vector<int> v {2,3,4,5,6};
    std::ranges::shuffle(v, rgen);  
    for(int x : v) { cout << x <<' '; }

    Sorting Sort

    sort sort

    a custom function(object) for comparing elements can be passed as 3rd argument

    std::vector<int> v {8,9,3,1,2,3,5,4,7,6};
    // sort subrange (as shown in image):
    sort(begin(v)+2, begin(v)+5);
    for(int x : v) { cout << x <<' '; }  // 8 9 1 2 3 3 4 5 7 6
    // sort entire vector:
    sort(begin(v), end(v));
    for(int x : v) { cout << x <<' '; }  // 1 2 3 3 4 5 6 7 8 9
    // sort vector in descending order:
    sort(begin(v), end(v), std::greater<>{});
    for(int x : v) { cout << x <<' '; }  // 9 8 7 6 5 4 3 3 2 1

    a custom function(object) for comparing elements can be passed as 2nd argument

    std::vector<int> range {3,1,2,3,5,4};
    std::ranges::sort(range);
    for(int x : range) { cout << x <<' '; }  // 1 2 3 3 4 5
    // sort in descending order:
    std::ranges::sort(range, std::greater<>{});
    for(int x : range) { cout << x <<' '; }  // 5 4 3 3 2 1

    stable_sort stable_sort

    stable ⇒ a stays before A (and E stays before e) even though they are equivalent with respect to case insensitive comparison

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 3rd argument

    #include <cctype>  // std::tolower
    auto compare_cicase_insensitive = [](char x, char y) {
      return std::tolower(x) < std::tolower(y); };
    std::string s = "gbaEAfec";
    stable_sort(begin(s)+1, begin(s)+7, compare_cicase_insensitive);
    cout << s;  // gaAbEefc

    stable ⇒ a stays before A (and E stays before e) even though they are equivalent with respect to case insensitive comparison

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 2nd argument

    #include <cctype>  // std::tolower
    auto compare_cicase_insensitive = [](char x, char y) {
      return std::tolower(x) < std::tolower(y); };
    std::string str = "baEAde";
    std::ranges::stable_sort(str, compare_cicase_insensitive);
    cout << str;  // aAbEed

    partial_sort / partial_sort_copy partial_sort_copy partial_sort

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 4th argument

    std::vector<int> v {7,4,6,2,3,5,1,9};
    // sort 4 smallest elements:
    auto const nth = begin(v) + 4;
    partial_sort(begin(v), nth, end(v));
    for(int x : v) { cout << x <<' '; }  // 1 2 3 4 7 6 5 9

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 3rd argument

    std::vector<int> v {7,4,6,2,3,5,1,9};
    // sort 4 smallest elements:
    auto const nth = begin(v) + 4;
    std::ranges::partial_sort(v, nth);
    for(int x : v) { cout << x <<' '; }  // 1 2 3 4 7 6 5 9

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 5th argument

    std::vector<int> in {6,2,3,5,1};
    // get sorted copy of 3 smallest elements:
    int const n = 3;
    std::vector<int> out; 
    out.resize(n);
    partial_sort_copy(begin(v), end(v),                   begin(v), end(v));
    for(int x : out) { cout << x <<' '; }  // 1 2 3
    // if output is larger than input:
    out.resize(100);
    auto const e = partial_sort_copy(begin(v), end(v),                   begin(v), end(v));
    out.erase(e, end(out));  // shrink to fit
    for(int x : out) { cout << x <<' '; }  // 1 2 3 5 6

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 3rd argument

    std::vector<int> in {6,2,3,5,1};
    // get sorted copy of 3 smallest elements:
    int const n = 3;
    std::vector<int> out; 
    out.resize(n); 
    std::ranges::partial_sort_copy(in, out);
    for(int x : out) { cout << x <<' '; }  // 1 2 3

    nth_element nth_element

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 4th argument

    std::vector<int> v {4,2,5,6,3,7,1};
    // get 5th element in sorted order
    int const n = 4;
    auto nth = begin(v) + n;
    nth_element(begin(v), nth, end(v));
    cout << *nth;  // 5

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 3rd argument

    std::vector<int> v {4,2,5,6,3,7,1};
    // get 5th element in sorted order
    int const n = 4;
    auto nth = begin(v) + n;
    std::ranges::nth_element(v, nth);
    cout << *nth;  // 5

    is_sorted is_sorted

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 3rd argument

    std::vector<int> v {2,3,4,5,6,1,0};
    // test subrange (as shown in image):
    cout << is_sorted(begin(v), begin(v)+5);  // true
    // test entire vector:
    cout << is_sorted(begin(v), end(v));  // false

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 2nd argument

    std::vector<int> v {2,3,4,5,6};
    cout << std::ranges::is_sorted(v);  // true

    is_sorted_until is_sorted_until

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 3rd argument

    std::vector<int> v {2,3,4,5,4,2,0,7,8};
    // test from 1st to 7th (as shown in image):
    auto i = is_sorted_until(begin(v), begin(v)+7);
    // print sorted subrange
    auto const print = [](int x){ cout << x << ' '; };
    std::for_each(begin(v), i, print);  // 2 3 4 5

    compares elements using operator < by default; a custom function(object) for comparing elements can be passed as 2nd argument

    std::vector<int> v {2,3,4,5,4,2,0};
    auto const i = std::ranges::is_sorted_until(v);
    // print sorted subrange
    auto const print = [](int x){ cout << x << ' '; };
    std::for_each(begin(v), i, print);  // 2 3 4 5

    Partitioning Partition

    partition / partition_copy partition_copy partition

    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> v {3,4,6,5,7,8,0};
    auto i = partition(begin(v), end(v), is_odd);
    auto const print = [](int x){ cout << x << ' '; };
    // print 1st subrange
    std::for_each(begin(v), i, print);  // 3 7 5
    // print 2nd subrange
    std::for_each(i, end(v), print);  // 6 4 8 0
    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> v {3,4,6,5,7,8,0};
    auto r2 = std::ranges::partition(v, is_odd);
    // print 2nd subrange
    for(int x : r2) { cout << x << ' '; }  // 6 4 8 0
    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> in {3,4,6,5,0};
    // ensure each output could hold all elements:
    std::vector<int> out1; out1.resize(in.size());
    std::vector<int> out2; out2.resize(in.size());
    auto ends = partition_copy(begin(in), end(in), begin(out1), begin(out2), is_odd);
    // resize partitions to fit content
    out1.erase(ends.first,  end(out1));
    out2.erase(ends.second, end(out2));
    // print partitions
    for(int x : out1) { cout << x << ' '; }  // 3 5
    for(int x : out2) { cout << x << ' '; }  // 4 6 0
    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> in {3,4,6,5,0};
    // ensure each output could hold all elements:
    std::vector<int> out1; out1.resize(in.size());
    std::vector<int> out2; out2.resize(in.size());
    auto ends = std::ranges::partition_copy(in, begin(out1), begin(out2), is_odd);
    // resize partitions to fit content
    out1.erase(ends.out1, end(out1));
    out2.erase(ends.out2, end(out2));
    // print partitions
    for(int x : out1) { cout << x << ' '; }  // 3 5
    for(int x : out2) { cout << x << ' '; }  // 4 6 0

    stable_partition stable_partition

    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> v {3,4,6,5,7,8,0};
    auto i = stable_partition(begin(v), end(v), is_odd);
    auto const print = [](int x){ cout << x << ' '; };
    // print 1st subrange
    std::for_each(begin(v), i, print);  // 3 5 7
    // print 2nd subrange
    std::for_each(i, end(v), print);  // 4 6 8 0
    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> v {3,4,6,5,7,8,0};
    auto r2 = std::ranges::stable_partition(v, is_odd);
    // print 2nd subrange
    for(int x : r2) { cout << x << ' '; }  // 4 6 8 0

    is_partitioned is_partitioned

    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> v {3,7,5,6,4,8,0};
    cout << is_partitioned(begin(v), end(v), is_odd);  // true
    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> v {3,7,5,6,4,8,0};
    cout << std::ranges::is_partitioned(v, is_odd);  // true

    partition_point partition_point

    performs a binary search for the first element in a partitioned input range for which f is false

    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> v {3,7,5,6,4,8,0};
    auto i = partition_point(begin(v), end(v), is_odd);
    auto const print = [](int x){ cout << x << ' '; };
    // print 1st subrange
    std::for_each(begin(v), i, print);  // 3 7 5
    // print 2nd subrange
    std::for_each(i, end(v), print);  // 6 4 8 0

    performs a binary search for the first element in a partitioned input range for which f is false

    auto const is_odd = [](int x) {   return (x & 1); };
    std::vector<int> v {3,7,5,6,4,8,0};
    auto i = std::ranges::partition_point(v, is_odd);
    auto const print = [](int x){ cout << x << ' '; };
    // print 1st subrange
    std::for_each(begin(v), i, print);  // 3 7 5
    // print 2nd subrange
    std::for_each(i, end(v), print);  // 6 4 8 0

    Permutations Permute

    prev_permutation / next_permutation prev_ / next_permutation prev_/next_permutation


    std::array<int,3> v {1,2,3};
    do {
      for(int x : v) { cout << x << ' '; } 
      cout << '\n';
    } while( std::next_permutation(begin(v),end(v)) );
    
    1 2 3 
    1 3 2 
    2 1 3 
    2 3 1 
    3 1 2 
    3 2 1

    std::array<int,3> v {1,2,3};
    do {
      for(int x : v) { cout << x << ' '; } 
      cout << '\n';
    } while( std::ranges::next_permutation(v).found );
    
    1 2 3 
    1 3 2 
    2 1 3 
    2 3 1 
    3 1 2 
    3 2 1

    is_permutation is_permutation

    std::vector<int> v1 {1,2,3,4};
    std::vector<int> v2 {4,2,1,3};
    std::vector<int> v3 {5,0,1,2};
    cout << is_permutation(begin(v1), end(v1), begin(v2));  // true
    cout << is_permutation(begin(v1), end(v1), begin(v3));  // false
    std::vector<int> v1 {1,2,3,4};
    std::vector<int> v2 {4,2,1,3};
    std::vector<int> v3 {5,0,1,2};
    cout << std::ranges::is_permutation(v1, v2);  // true
    cout << std::ranges::is_permutation(v1, v3);  // false