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: 2binary_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.

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 |
| Position iterator |
Count a condition |
| Number of matches |
Test a range condition |
| Boolean |
Get both extremes |
| 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.

Choose an algorithm by effect, iterator requirement and cost
Goal | Algorithm | Changes input? | Key requirement | Typical cost |
|---|---|---|---|---|
First match |
| No | Input iterator | Linear comparisons |
Count by rule |
| No | Input iterator and predicate | Linear predicate calls |
Reorder |
| Yes | Random-access iterator |
|
Membership |
| No | Sorted range | Logarithmic comparisons on random-access data |
Change each value |
| Yes | Valid output range | Linear applications |
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 | Names may be unavailable | Add |
Forgetting | Lookup fails | Qualify the name |
Passing | Final element is excluded | Pass |
Binary searching before sorting | Preconditions are violated | Sort with the same comparison first |
Dereferencing a failed | The result equals | Compare before dereferencing |
Expecting | Only a logical prefix is formed | Call |
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:
Sorting
{5, 2, 5, 1, 9}gives{1, 2, 5, 5, 9}. Thereforelower_bound(5)is index2,upper_bound(5)is index4, and the count is4 - 2 = 2.Removing evens from
{3, 8, 5, 2, 7}leaves logical prefix{3, 5, 7}, withnewEndat index3beforeerase.std::sortrejectsstd::list<int>::iteratorbecause 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.




