C++ - Algorithms & Ranges Deep Dive
Overview
Estimated time: 70–90 minutes
Master the algorithms toolbox: transform, accumulate, partition/remove_if, sorting, and composing C++20 ranges pipelines. Learn when to copy vs view, projections, and performance tips.
Learning Objectives
- Use key algorithms: transform, accumulate, copy_if/remove_if, partition, sort/stable_sort with comparators.
- Build expressive ranges pipelines with views::filter, transform, take/drop; collect into containers safely.
- Apply erase-remove and understand iterator invalidation and complexity.
Prerequisites
Transform and accumulate
#include <vector>
#include <numeric>
#include <algorithm>
#include <iostream>
int main(){
std::vector v{1,2,3,4};
std::vector sq(v.size());
std::transform(v.begin(), v.end(), sq.begin(), [](int x){ return x*x; });
int sum = std::accumulate(sq.begin(), sq.end(), 0);
std::cout << sum << "\n"; // 30
}
Expected Output: 30
Filter with copy_if and erase-remove
#include <vector>
#include <algorithm>
#include <iostream>
int main(){
std::vector xs{1,2,3,4,5,6};
std::vector out;
std::copy_if(xs.begin(), xs.end(), std::back_inserter(out), [](int x){return x%2==0;});
xs.erase(std::remove_if(xs.begin(), xs.end(), [](int x){return x%2==0;}), xs.end());
for (int x: out) std::cout << x << ' '; std::cout << "\n"; // 2 4 6
for (int x: xs) std::cout << x << ' '; // 1 3 5
}
Partition and sort
#include <vector>
#include <algorithm>
#include <iostream>
int main(){
std::vector v{5,1,4,2,3};
std::partition(v.begin(), v.end(), [](int x){return x%2==0;}); // evens first
std::sort(v.begin(), v.end());
for (int x : v) std::cout << x << ' ';
}
Expected Output: 1 2 3 4 5
Ranges pipelines (C++20)
#include <vector>
#include <ranges>
#include <iostream>
int main(){
std::vector v{1,2,3,4,5,6};
auto pipe = v | std::views::filter([](int x){ return x%2==0; })
| std::views::transform([](int x){ return x*x; })
| std::views::take(2);
std::vector out; for (int x : pipe) out.push_back(x);
for (int x : out) std::cout << x << ' '; // 4 16
}
Beginner Boosters
#include
#include
#include
int main(){
std::vector v{1,2,3,4,5};
std::cout << std::count_if(v.begin(), v.end(), [](int x){return x%2==0;}) << "\n"; // 2
std::cout << (std::all_of(v.begin(), v.end(), [](int x){return x>0;})?"yes":"no") << "\n"; // yes
}
#include
#include
#include
int main(){
std::vector v{0,0,1,2,3,0};
auto pipe = v | std::views::drop_while([](int x){return x==0;})
| std::views::take_while([](int x){return x>0;});
for (int x : pipe) std::cout << x << ' '; // 1 2 3
}
Best practices
- Prefer algorithms over manual loops for clarity and correctness.
- Remember erase-remove to truly shrink containers.
- With ranges views, be aware of dangling views; materialize into a container when needed.
Common Pitfalls
- Iterators invalidated after erase/sort; don’t reuse stale iterators.
- Capturing references to temporary ranges in long-lived views; copy when necessary.
Checks for Understanding
- What does remove_if return and why must you call erase?
- When should you materialize a view into a container?
Show answers
- It returns the new logical end after moving kept elements forward; erase to shrink the container.
- When you need ownership, random access, or long-lived data independent of the source.
Exercises
- Use ranges to produce the first three squares of even numbers from 1..20.
- Partition a vector by a predicate, then stable_sort each partition with a custom comparator.