Algorithm Basics
Master fundamental STL algorithms like find, count, copy, and fill that work with any container
Learn how to use STL algorithms to write more expressive, efficient code that works with any container type.
A Simple Example
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> numbers{10, 20, 30, 40, 50, 30, 60};
// Find first occurrence
auto it = std::find(numbers.begin(), numbers.end(), 30);
if (it != numbers.end()) {
std::cout << "Found 30 at position: "
<< std::distance(numbers.begin(), it) << "\n";
}
// Count occurrences
int count = std::count(numbers.begin(), numbers.end(), 30);
std::cout << "Count of 30: " << count << "\n";
// Count with condition
int countAbove25 = std::count_if(numbers.begin(), numbers.end(),
[](int n) { return n > 25; });
std::cout << "Numbers > 25: " << countAbove25 << "\n";
// Check if all/any/none match condition
bool allPositive = std::all_of(numbers.begin(), numbers.end(),
[](int n) { return n > 0; });
std::cout << "All positive: " << std::boolalpha << allPositive << "\n";
// Fill with value
std::vector<int> zeros(5);
std::fill(zeros.begin(), zeros.end(), 7);
std::cout << "Filled: ";
for (int n : zeros) std::cout << n << " ";
std::cout << "\n";
return 0;
}
Breaking It Down
std::find() - Search for a Value
- What it does: Searches for the first occurrence of a value in a range
- Returns: Iterator to the found element, or end() if not found
- Use for: Checking if an element exists, getting its position
-
Remember: Always check
if (it != container.end())before using the result
std::count() and std::count_if() - Count Elements
- std::count: Counts how many times a specific value appears
- std::count_if: Counts elements matching a condition (using a lambda or function)
- Returns: The count as an integer
- Remember: count_if is powerful when combined with lambdas for custom conditions
std::all_of(), std::any_of(), std::none_of() - Test Conditions
- all_of: Returns true if ALL elements match the condition
- any_of: Returns true if ANY element matches the condition
- none_of: Returns true if NO elements match the condition
- Remember: These are more readable than writing loops with flags
std::fill() - Set All Elements to a Value
- What it does: Sets all elements in a range to the same value
- Syntax: std::fill(begin, end, value)
- Use for: Initializing containers, resetting values
- Remember: There is also fill_n() for filling N elements
Why This Matters
- STL algorithms represent decades of optimization and testing by experts.
- Using `std::find()` instead of writing your own loop means less code to write, test, and debug.
- These algorithms work with any container through iterators, making them incredibly versatile.
- They are often more efficient than hand-written loops thanks to compiler optimizations and carefully chosen implementations.
Critical Insight
The erase-remove idiom looks weird at first: container.erase(std::remove(...), container.end()). Here is why it works: std::remove() does not actually erase elements because it only has iterators, not the container itself. Instead, it moves all the elements you want to keep to the front and returns an iterator to the new "end". Then erase() actually removes everything from that point to the real end. It is a two-step dance that is more efficient than erasing elements one by one!
Best Practices
Always check iterator validity: After std::find(), check if (it != container.end()) before dereferencing.
Use algorithm + lambda for clarity: std::count_if(v.begin(), v.end(), [](int x) { return x > 0; }) is more readable than a manual loop.
Prefer algorithms over raw loops: They express intent clearly and are often optimized by compilers.
Use the erase-remove idiom correctly: v.erase(std::remove(v.begin(), v.end(), value), v.end()) to actually remove elements.
Common Mistakes
Forgetting to check return value: Dereferencing an end() iterator from std::find() causes undefined behavior. Always check first.
Using std::remove() alone: std::remove() does not actually erase elements - it just moves them. You must call erase() to actually remove them.
Using binary_search on unsorted data: Algorithms like binary_search, lower_bound, and upper_bound require sorted data to work correctly.
Not including <algorithm>: Forgetting to #include <algorithm> will cause compile errors when using these functions.
Debug Challenge
This code tries to find an element but has a bug. Click the highlighted line to fix it:
Quick Quiz
- What does std::find() return if the element is not found?
- Why do you need both std::remove() and erase()?
- Which algorithm would you use to check if all elements in a vector are positive?
Practice Playground
Time to try out what you just learned! Play with the example code below, experiment by making changes and running the code to deepen your understanding.
Output:
Error:
Lesson Progress
- Fix This Code
- Quick Quiz
- Practice Playground - run once