Algorithms Header in C++: Sort, Search and Transform with Runnable Examples

Learn the iterator-range model behind C++ standard algorithms through complete programs for sorting, searching, transforming and erase-remove.

KnowledgeGate Team

Exam prep & CS education

Updated 16 Aug 20267 min read

You can write a loop to sort, search or filter a vector, but the standard library often expresses it more clearly. The challenge is choosing an algorithm and understanding why calls use begin() and end(). Two facts settle most of it: every call works on the half-open range [first, last), and an algorithm reorders or overwrites elements without ever changing the container's size. The header is <algorithm>, singular, though it contains many algorithms.

C++ <algorithm> and the iterator-range mental model

<algorithm> provides generic operations over iterator ranges. These functions are not std::vector methods; they work with containers whose iterators meet each algorithm's requirements. That same iterator-range vocabulary reappears across the data-structure practice in the Coding & DSA category, so it is worth learning once and reusing.

Most calls use the half-open range [first, last): first is included and last excluded. For std::vector<int> values{9, 4, 7, 4, 1, 8}, values.begin() points to index 0; values.end() points beyond index 5. Thus std::sort(values.begin(), values.end()) covers all six elements. Using values.end() - 1 covers only indices 0 through 4, excluding the final 8.

The main example uses <algorithm> for algorithms, <iostream> for output and <vector> for storage. Algorithms can change values or order within a range, but usually not container size. Shrinking a vector requires erase.

std::sort, binary_search and bounds in one runnable trace

This complete C++17 program sorts once, then searches the ordered range:

#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> values{9, 4, 7, 4, 1, 8};

    std::cout << "Original:";
    for (int value : values) std::cout << ' ' << value;
    std::cout << '\n';

    std::sort(values.begin(), values.end());

    std::cout << "Sorted:";
    for (int value : values) std::cout << ' ' << value;
    std::cout << '\n';

    bool hasSeven = std::binary_search(values.begin(), values.end(), 7);
    auto firstFour = std::lower_bound(values.begin(), values.end(), 4);
    auto afterFour = std::upper_bound(values.begin(), values.end(), 4);

    std::cout << std::boolalpha;
    std::cout << "Has 7: " << hasSeven << '\n';
    std::cout << "First 4 index: " << firstFour - values.begin() << '\n';
    std::cout << "After 4 index: " << afterFour - values.begin() << '\n';
    std::cout << "Number of 4s: " << afterFour - firstFour << '\n';
}

Exact output:

Original: 9 4 7 4 1 8
Sorted: 1 4 4 7 8 9
Has 7: true
First 4 index: 1
After 4 index: 3
Number of 4s: 2

binary_search answers only whether a value is present. The bound functions return insertion-position iterators. Here they expose the duplicate range [1, 3), whose length is 3 - 1 = 2.

All three search algorithms require a range already ordered by the same comparison rule. Calling them on the original unsorted vector violates that precondition.

Iterator diagram of the vector before and after std::sort, with lower_bound and upper_bound marking the duplicate 4s in range [1, 3).

find, count_if and minmax_element inspect a range

With {1, 4, 4, 7, 8, 9}, std::find(values.begin(), values.end(), 7) returns the iterator at index 3. Compare it with values.end() before dereferencing. Unlike binary_search, find needs no ordering and returns a position, but searches linearly.

std::count_if(values.begin(), values.end(), [](int x) { return x % 2 == 0; }) matches 4, 4, 8, so it returns 3. std::minmax_element returns a pair of iterators whose values are 1 and 9. Guard an empty range before dereferencing, because both result iterators would equal end().

Goal

Algorithm

Result

First equal value

find

Position iterator

Count a condition

count_if

Number of matches

Test a range condition

all_of or any_of

Boolean

Get both extremes

minmax_element

Pair of iterators

A predicate is simply a callable yes-or-no rule, such as the even-number lambda above. On {1, 4, 4, 7, 8, 9} that same predicate makes std::all_of return false, because 1 is odd, while std::any_of returns true. None of these operations needs to rearrange the vector.

transform and erase-remove change values and size correctly

This second runnable program changes every score, removes low scores and reverses the result:

#include <algorithm>
#include <iostream>
#include <vector>

void print(const std::vector<int>& values) {
    for (int value : values) std::cout << value << ' ';
    std::cout << '\n';
}

int main() {
    std::vector<int> scores{38, 52, 67, 71, 84};
    std::transform(scores.begin(), scores.end(), scores.begin(),
                   [](int score) { return score + 5; });
    print(scores);                         // 43 57 72 76 89

    auto newEnd = std::remove_if(scores.begin(), scores.end(),
                                 [](int score) { return score < 60; });
    scores.erase(newEnd, scores.end());
    print(scores);                         // 72 76 89

    std::reverse(scores.begin(), scores.end());
    print(scores);                         // 89 76 72
}

Writing to scores.begin() is safe because the output range already has five positions. An algorithm does not automatically grow an undersized destination.

After remove_if, the logical prefix is {72, 76, 89} and newEnd - scores.begin() is 3, but scores.size() remains 5. The last two cells hold valid but unspecified values, so there is no correct reason to print or guess them. After scores.erase(newEnd, scores.end()), the vector is exactly {72, 76, 89} with size 3. Iterators at or after the erased position must not be reused after vector::erase.

Erase-remove diagram in three panels: the scores after transform, the kept prefix before newEnd with two unspecified tail cells while size stays 5, then the size-3 vector after erase.

Choose an algorithm by effect, iterator requirement and cost

Goal

Algorithm

Changes input?

Key requirement

Typical cost

First match

find

No

Input iterator

Linear comparisons

Count by rule

count_if

No

Input iterator and predicate

Linear predicate calls

Reorder

sort

Yes

Random-access iterator

O(n log n) comparisons

Membership

binary_search

No

Sorted range

Logarithmic comparisons on random-access data

Change each value

transform

Yes

Valid output range

Linear applications

Reverse

reverse

Yes

Bidirectional iterator

Linear swaps

Iterator requirements matter. std::sort accepts std::vector<int> iterators because they support random access. std::list<int> iterators do not, so std::sort(items.begin(), items.end()) is ill-formed; a list provides items.sort() instead.

If stability and in-place behaviour affect your choice, read Sorting Algorithms Compared: complexity, stability, and the n log n lower bound. std::sort gives a standard ordering operation, while that guide compares sorting families. Do not assume every standard-library vendor uses one particular implementation algorithm.

Common <algorithm> errors and their exact fixes

Mistake

What goes wrong

Fix

Missing <algorithm>

Names may be unavailable

Add #include <algorithm>

Forgetting std::

Lookup fails

Qualify the name

Passing end() - 1

Final element is excluded

Pass end()

Binary searching before sorting

Preconditions are violated

Sort with the same comparison first

Dereferencing a failed find

The result equals end()

Compare before dereferencing

Expecting remove_if to shrink

Only a logical prefix is formed

Call erase(newEnd, end())

For the main values, sorting only [begin, end - 1) produces {1, 4, 4, 7, 9, 8}, which is not globally sorted. For scores, remove_if alone creates the logical prefix {72, 76, 89} but leaves size() == 5.

A valid descending comparator is [](int a, int b) { return a > b; }. It orders the main vector as {9, 8, 7, 4, 4, 1}. Using a >= b is invalid because equal values would compare before each other, breaking strict ordering. Later bound calls on that descending range must receive the same comparator.

How exams and interviews test the C++ algorithms header

Common questions ask you to predict an iterator-range program, select an algorithm, identify a broken precondition, compare linear and binary search, or explain the two erase-remove steps. This is different from an algorithm-design method such as the one in Greedy algorithms: strategy, exchange arguments and classic problems.

Try these checks:

  1. Sorting {5, 2, 5, 1, 9} gives {1, 2, 5, 5, 9}. Therefore lower_bound(5) is index 2, upper_bound(5) is index 4, and the count is 4 - 2 = 2.

  2. Removing evens from {3, 8, 5, 2, 7} leaves logical prefix {3, 5, 7}, with newEnd at index 3 before erase.

  3. std::sort rejects std::list<int>::iterator because it is not random access.

For coding practice, rotate {10, 20, 30, 40, 50} left by two positions with std::rotate; the expected output is {30, 40, 50, 10, 20}. Then partition {1, 2, 3, 4, 5, 6} with an even predicate. Check only that all evens appear before all odds, because std::partition does not promise one exact internal order.

Coding For Placements is a structured route for broader C++, DSA and coding-question practice.

The short version and the next runnable step

Remember four rules: include the right header, express work as a half-open range, check ordering and iterator preconditions, and separate rearranging a range from changing container size. The main result is {9, 4, 7, 4, 1, 8} becoming {1, 4, 4, 7, 8, 9}, with the two 4s occupying [1, 3).

Type the first complete program and predict all six output lines before compiling. Change the searched value from 7 to 6. Then use the valid descending comparator and give the bound calls that same comparator. Explain every iterator position instead of merely pasting the code.

The C++ Programming course is the focused next step if you want the language sequence organised. If this header is your only gap, complete the two exercises and three checks here first.