๐งฐ STL Algorithms: Your Magic Toolbox for C++
Imagine you have a huge toy box filled with LEGO blocks. Now imagine someone gave you a magic wand that could instantly sort all the red blocks together, find every blue block, or count how many yellow blocks you haveโwithout you touching a single piece!
Thatโs exactly what STL Algorithms are. Theyโre pre-built magic spells that work on your data containers (like vectors and arrays) to do amazing things in just one line of code!
๐ The Big Picture
Think of STL Algorithms as helpful robots that live in the <algorithm> and <numeric> headers. You just tell them:
- Where to start (beginning of your data)
- Where to stop (end of your data)
- What to do (sort, find, count, etc.)
And BOOM! They do all the hard work for you!
#include <algorithm>
#include <numeric>
๐ Chapter 1: Non-Modifying Algorithms
๐ What Are They?
Non-modifying algorithms are like detectives. They look at your data, investigate it, but they never change anything. They just give you answers!
Think of it like counting cookies in a jar. You look inside, count them, but you donโt eat any (even though itโs tempting!).
๐ find โ The Treasure Hunter
find searches for ONE specific item and tells you where it is.
vector<int> nums = {5, 10, 15, 20};
auto it = find(nums.begin(),
nums.end(),
15);
// it points to 15!
Analogy: Like finding your favorite red crayon in a crayon box!
๐ข count โ The Counter
count tells you how many times something appears.
vector<int> nums = {1, 2, 2, 3, 2};
int result = count(nums.begin(),
nums.end(),
2);
// result = 3 (three 2's!)
Analogy: Like counting how many gummy bears are red!
โ
all_of, any_of, none_of โ The Checkers
These are your yes/no detectives:
all_of: Are ALL items matching? (Everyone ate vegetables?)any_of: Is AT LEAST ONE matching? (Anyone finished homework?)none_of: Is NOTHING matching? (Nobody has a pet dragon?)
vector<int> nums = {2, 4, 6, 8};
bool allEven = all_of(nums.begin(),
nums.end(),
[](int n){ return n%2==0; });
// true! All are even!
๐ฏ for_each โ The Visitor
for_each visits every item and does something with it (without changing the container itself).
vector<int> nums = {1, 2, 3};
for_each(nums.begin(),
nums.end(),
[](int n){ cout << n << " "; });
// Prints: 1 2 3
๐ Chapter 2: Modifying Algorithms
๐จ What Are They?
Modifying algorithms are like artists. They actually CHANGE your data! They can copy, replace, fill, transform, or remove things.
Think of it like a painter who transforms a blank canvas into a beautiful picture!
๐ copy โ The Duplicator
copy makes a duplicate of your data into another place.
vector<int> src = {1, 2, 3};
vector<int> dest(3);
copy(src.begin(),
src.end(),
dest.begin());
// dest = {1, 2, 3}
Analogy: Like making a photocopy of your drawing!
๐ transform โ The Shape-Shifter
transform changes every item using a rule you give it.
vector<int> nums = {1, 2, 3};
transform(nums.begin(),
nums.end(),
nums.begin(),
[](int n){ return n * 2; });
// nums = {2, 4, 6}
Analogy: Like a machine that doubles every coin you put in!
๐จ fill โ The Painter
fill paints everything with the same color (value).
vector<int> nums(5);
fill(nums.begin(),
nums.end(),
7);
// nums = {7, 7, 7, 7, 7}
๐ replace โ The Fixer
replace finds all occurrences of something and swaps them.
vector<int> nums = {1, 2, 2, 3};
replace(nums.begin(),
nums.end(),
2, 99);
// nums = {1, 99, 99, 3}
๐๏ธ remove โ The Eraser
remove pushes unwanted items to the end (doesnโt actually delete themโuse erase after!).
vector<int> nums = {1, 2, 3, 2, 4};
auto newEnd = remove(nums.begin(),
nums.end(),
2);
nums.erase(newEnd, nums.end());
// nums = {1, 3, 4}
๐ reverse โ The Mirror
reverse flips your data backwards!
vector<int> nums = {1, 2, 3, 4};
reverse(nums.begin(),
nums.end());
// nums = {4, 3, 2, 1}
๐ฒ shuffle โ The Mixer
shuffle randomly mixes up your data like shuffling cards!
vector<int> nums = {1, 2, 3, 4, 5};
random_device rd;
mt19937 g(rd());
shuffle(nums.begin(),
nums.end(),
g);
// nums in random order!
๐ Chapter 3: Sorting Algorithms
๐ What Are They?
Sorting algorithms put things in order! Like organizing your bookshelf from shortest to tallest books.
๐ sort โ The Organizer
sort arranges everything in order (smallest to largest by default).
vector<int> nums = {5, 2, 8, 1, 9};
sort(nums.begin(),
nums.end());
// nums = {1, 2, 5, 8, 9}
Custom sorting (largest to smallest):
sort(nums.begin(),
nums.end(),
greater<int>());
// nums = {9, 8, 5, 2, 1}
๐
partial_sort โ The Podium Maker
partial_sort only sorts the first N items. Perfect for finding โtop 3 scoresโ!
vector<int> nums = {5, 2, 8, 1, 9, 3};
partial_sort(nums.begin(),
nums.begin() + 3,
nums.end());
// First 3 are smallest: {1, 2, 3, ...}
๐๏ธ nth_element โ The Median Finder
nth_element finds the Nth element if the data were sorted.
vector<int> nums = {5, 2, 8, 1, 9};
nth_element(nums.begin(),
nums.begin() + 2,
nums.end());
// nums[2] is now the median!
โ
is_sorted โ The Inspector
is_sorted checks if your data is already in order.
vector<int> nums = {1, 2, 3, 4};
bool sorted = is_sorted(nums.begin(),
nums.end());
// sorted = true!
๐ stable_sort โ The Respectful Organizer
stable_sort sorts but keeps equal items in their original order.
// If two students have same score,
// stable_sort keeps them in
// original order!
๐ Chapter 4: Searching Algorithms
๐ฆ What Are They?
Searching algorithms help you find things FAST! But thereโs a catchโsome of them need your data to be sorted first.
โก binary_search โ The Speed Finder
binary_search checks if something exists (data MUST be sorted!).
vector<int> nums = {1, 2, 3, 4, 5};
bool found = binary_search(nums.begin(),
nums.end(),
3);
// found = true!
Why so fast? It cuts the search in half each time, like a โhigher or lowerโ guessing game!
๐ lower_bound โ The First Finder
lower_bound finds where a value would fit (first position โฅ value).
vector<int> nums = {1, 2, 4, 4, 5};
auto it = lower_bound(nums.begin(),
nums.end(),
4);
// Points to first 4
๐ upper_bound โ The Next Finder
upper_bound finds the first position > value.
vector<int> nums = {1, 2, 4, 4, 5};
auto it = upper_bound(nums.begin(),
nums.end(),
4);
// Points to 5 (after all 4's)
๐ฏ equal_range โ The Range Finder
equal_range gives you BOTH lower and upper bounds at once!
vector<int> nums = {1, 2, 4, 4, 5};
auto range = equal_range(nums.begin(),
nums.end(),
4);
// range.first โ first 4
// range.second โ after last 4
๐ Chapter 5: Numeric Algorithms
๐ข What Are They?
Numeric algorithms do math on your data! They live in <numeric> header.
Think of them as calculators built for collections!
โ accumulate โ The Adder
accumulate adds up all values (or applies any operation).
#include <numeric>
vector<int> nums = {1, 2, 3, 4};
int sum = accumulate(nums.begin(),
nums.end(),
0);
// sum = 10
Custom operation (multiply all):
int product = accumulate(nums.begin(),
nums.end(),
1,
multiplies<int>());
// product = 24
๐ partial_sum โ The Running Total
partial_sum calculates cumulative sums.
vector<int> nums = {1, 2, 3, 4};
vector<int> result(4);
partial_sum(nums.begin(),
nums.end(),
result.begin());
// result = {1, 3, 6, 10}
โ adjacent_difference โ The Gap Finder
adjacent_difference finds the difference between neighbors.
vector<int> nums = {1, 3, 6, 10};
vector<int> diff(4);
adjacent_difference(nums.begin(),
nums.end(),
diff.begin());
// diff = {1, 2, 3, 4}
โ๏ธ inner_product โ The Dot Product
inner_product multiplies pairs and sums them (like dot product in math!).
vector<int> a = {1, 2, 3};
vector<int> b = {4, 5, 6};
int result = inner_product(a.begin(),
a.end(),
b.begin(),
0);
// result = 1*4 + 2*5 + 3*6 = 32
๐ข iota โ The Filler
iota fills a range with increasing values.
vector<int> nums(5);
iota(nums.begin(),
nums.end(),
1);
// nums = {1, 2, 3, 4, 5}
๐ Chapter 6: Execution Policies
๐ What Are They?
Execution policies tell algorithms HOW to run. Theyโre like choosing between:
- ๐ถ Walking (one step at a time)
- ๐ Running with friends (everyone helps at once!)
Imagine cleaning your room alone vs. with 10 friends helpingโsame task, MUCH faster!
๐ The Three Policies
Include the header:
#include <execution>
| Policy | Symbol | What It Does |
|---|---|---|
| Sequential | std::execution::seq |
One item at a time (normal) |
| Parallel | std::execution::par |
Multiple items at once! |
| Parallel Unsequenced | std::execution::par_unseq |
Maximum speed (SIMD too!) |
๐ก Example: Parallel Sorting
#include <execution>
vector<int> nums = {5, 2, 8, 1, 9};
sort(execution::par,
nums.begin(),
nums.end());
// Sorted using multiple CPU cores!
โ ๏ธ When to Use Parallel?
| โ Use Parallel | โ Donโt Use Parallel |
|---|---|
| Large datasets (10000+ items) | Small datasets |
| Independent operations | Operations that depend on order |
| CPU-bound tasks | Memory-bound tasks |
๐ฏ Quick Reference Diagram
graph TD A["STL Algorithms"] --> B["Non-Modifying"] A --> C["Modifying"] A --> D["Sorting"] A --> E["Searching"] A --> F["Numeric"] A --> G["Execution Policies"] B --> B1["find, count"] B --> B2["all_of, any_of"] B --> B3["for_each"] C --> C1["copy, transform"] C --> C2["fill, replace"] C --> C3["remove, reverse"] D --> D1["sort, stable_sort"] D --> D2["partial_sort"] D --> D3["nth_element"] E --> E1["binary_search"] E --> E2["lower/upper_bound"] E --> E3["equal_range"] F --> F1["accumulate"] F --> F2["partial_sum"] F --> F3["iota"] G --> G1["seq"] G --> G2["par"] G --> G3["par_unseq"]
๐ The Magic Formula
Every STL algorithm follows this pattern:
algorithm_name(start, end, ...other_args);
- start = Where to begin (usually
.begin()) - end = Where to stop (usually
.end()) - โฆother_args = What else the algorithm needs
๐ You Did It!
Youโve just learned the most powerful tools in C++! These algorithms are:
- โ Tested by thousands of experts
- โ Optimized for maximum speed
- โ Safe and reliable
Instead of writing loops yourself, let these magic helpers do the work!
Remember: Great programmers donโt write more codeโthey write SMARTER code. And using STL algorithms is the smartest choice you can make! ๐
