Stl Algorithms
By the end of this lesson you'll replace hand-written loops with the C++ Standard Library's algorithm and numeric tools — sorting with your own rules, searching, summing, transforming, and safely deleting elements — using one line where you used to write fifteen.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Think of STL algorithms as power tools . You could cut every plank with a hand saw (your own for loop), but a builder reaches for the right power tool: a circular saw to cut ( sort ), a stud finder to locate ( find ), a tape measure to total up ( accumulate ). Each tool clamps onto a stretch of work — that's the iterator range , from begin() to end() . You supply the rule (a lambda : "cut here", "keep this one") and the tool does the repetitive work, faster and with fewer mistakes than doing it by hand.
1. Sort, Find & Count
std::sort rearranges a range in place — ascending by default. To sort by your rule, pass a third argument: a comparator . A comparator is a lambda that takes two elements and returns a bool answering one question — "should a come before b ?" Return a b and you've flipped it to descending. find hunts for an exact value and hands back an iterator (compare it to end() to check for a miss), while count and count_if tally matches. Read this worked example, run it, then you'll write your own.
Your turn. The program below is almost complete — fill in the two blanks marked ___ using the hints, then run it and check it against the expected output.
2. Accumulate, Transform & for_each
std::accumulate (from numeric , not algorithm ) folds a whole range into a single value — its third argument is both the starting total and the type of the result. std::transform applies a function to every element and writes the results into another range. std::for_each runs an action on each element without producing a new range. And min_element / max_element return an iterator to the smallest or largest value — remember to dereference it with * to read the value out.
Now you try. Total a list of workout minutes, then convert each one to hours. Fill in the two blanks — watch the type on the accumulate seed and the division:
3. Deleting Elements: the Erase-Remove Idiom
This is the one that surprises everybody. std::remove and std::remove_if do not actually delete anything . An algorithm only sees a pair of iterators — it has no power to resize the container. So remove just shuffles the elements you're keeping to the front and returns an iterator to the new logical end ; the leftover slots are still there. To truly shrink the container you pass that iterator to the container's own erase() method. Doing both together is the famous erase-remove idiom .
No blanks this time — just a brief and an outline to keep you on track. Combine sort , min_element / max_element , accumulate , and count_if into one small report. Build it, run it, and check your output against the example in the comments.
Practice quiz
Which header is std::sort, std::find, and std::count_if declared in?
- <numeric>
- <vector>
- <algorithm>
- <functional>
Answer: <algorithm>. sort, find, count_if, transform, for_each, remove_if and min/max_element all live in <algorithm>.
Which header does std::accumulate live in?
- <numeric>
- <algorithm>
- <vector>
- <cmath>
Answer: <numeric>. accumulate lives in <numeric>, not <algorithm> — a common include mistake.
What should a comparator lambda passed to std::sort return?
- The larger of the two elements
- An int: -1, 0, or 1
- The sorted range
- A bool answering 'should a come before b?'
Answer: A bool answering 'should a come before b?'. A comparator returns a bool — true when a should sort before b. Use a < b for ascending, a > b for descending.
To sort a vector in DESCENDING order, the comparator should return:
- a < b
- a > b
- a <= b
- a == b
Answer: a > b. Returning a > b means bigger elements come first, giving descending order.
What does std::find return?
- An iterator to the element, or end() if not found
- The matching value, or 0 if not found
- The index of the element
- A bool
Answer: An iterator to the element, or end() if not found. find returns an iterator; compare it to end() to detect a miss.
What is the result of accumulate(v.begin(), v.end(), 0) for v = {1299, 2499, 599, 3999, 899}?
- 5
- 3999
- 9295
- 0
Answer: 9295. accumulate folds the range starting from the seed 0: 1299+2499+599+3999+899 = 9295.
Why does the seed type in accumulate matter, e.g. 0 vs 0.0?
- It controls the iteration order
- It fixes the result type — 0 sums as int and truncates decimals, 0.0 sums as double
- 0.0 is invalid for accumulate
- It changes which header is needed
Answer: It fixes the result type — 0 sums as int and truncates decimals, 0.0 sums as double. The seed sets the accumulation type; seeding with int 0 truncates decimals, while 0.0 keeps them.
What does std::transform do?
- Sorts a range in place
- Removes elements that match a predicate
- Counts matching elements
- Applies a function to every element and writes results into another range
Answer: Applies a function to every element and writes results into another range. transform maps each input element through a function into an output range.
What do min_element and max_element return?
- The smallest/largest value directly
- An iterator to the smallest/largest element — dereference with * to read the value
- An index
- A sorted copy of the range
Answer: An iterator to the smallest/largest element — dereference with * to read the value. They return iterators; you write *max_element(v.begin(), v.end()) to get the value.
Why must remove_if be paired with the container's erase() (the erase-remove idiom)?
- erase is faster than remove_if
- remove_if deletes the wrong elements without erase
- remove_if only shifts kept elements forward and returns the new logical end; it can't resize the container
- erase sorts the range first
Answer: remove_if only shifts kept elements forward and returns the new logical end; it can't resize the container. Algorithms see only iterators, so remove_if can't shrink the container — erase() does the actual shrinking.