STL Algorithms
Written and reviewed by Gagan Bhardwaj · Senior IT Faculty · 15+ years’ experience
The STL Algorithm Model
Standard algorithms separate what operation to perform from how data is stored. A container owns elements; iterators describe a range; an algorithm reads or modifies that range.
#include <algorithm>
#include <vector>
std::vector<int> values{7, 2, 9, 4};
std::sort(values.begin(), values.end());The same find or count_if can work with vector, array, deque and many user-defined ranges when their iterators meet the requirements. Algorithms do not magically include their headers; use <algorithm> for most sequence algorithms and <numeric> for accumulation and related numeric operations.
| Family | Examples |
|---|---|
| Non-modifying queries | find, count, all_of |
| Copy/transform | copy, transform, replace |
| Reordering | reverse, rotate, shuffle |
| Sorting/searching | sort, lower_bound, binary_search |
| Numeric | accumulate, iota, inner_product |
Start with the STL architecture guide if containers and iterators are new.
Iterator Ranges, Requirements and C++20 Ranges
Classic algorithms usually accept [first,last). The first position is included; last is one past the range and must not be dereferenced.
auto first = values.begin();
auto last = values.end();
std::reverse(first, last);| Algorithm | Important iterator requirement |
|---|---|
find/count | Input iterator |
copy | Readable input + writable output |
reverse | Bidirectional iterator |
sort/nth_element | Random-access iterator |
This explains why std::sort works with vector but not list. Study iterator categories for the complete model.
C++20 range algorithms can accept a whole range and use projections:
#include <ranges>
struct Student { std::string name; int mark; };
std::ranges::sort(students, std::greater{}, &Student::mark);Many ranges algorithms return structured result types rather than a single iterator. Views may be lazy and often refer to another range, so the source lifetime must outlast view use.
Searching, Counting and Predicates
auto found = std::find(values.begin(), values.end(), 9);
if (found != values.end()) {
std::cout << "Index: " << std::distance(values.begin(), found);
}
const auto evens = std::count_if(values.begin(), values.end(),
[](int n) { return n % 2 == 0; });
const bool all_positive = std::all_of(values.begin(), values.end(),
[](int n) { return n > 0; });| Algorithm | Meaning |
|---|---|
find/find_if | First matching position or end |
count/count_if | Number of matches |
all_of | Every element satisfies predicate |
any_of | At least one satisfies predicate |
none_of | No element satisfies predicate |
mismatch | First differing pair |
A predicate must not invalidate the range or unpredictably modify values used by the algorithm. Capture only what is needed and prefer pure, readable lambdas.
Copy, Transform, Replace and Remove
std::vector<int> doubled(values.size());
std::transform(values.begin(), values.end(), doubled.begin(),
[](int n) { return n * 2; });
std::replace(values.begin(), values.end(), -1, 0);
std::reverse(values.begin(), values.end());The destination of copy/transform must have enough space, or use an insertion iterator:
std::vector<int> result;
result.reserve(values.size());
std::copy_if(values.begin(), values.end(),
std::back_inserter(result),
[](int n) { return n >= 0; });Erase–remove correctly
auto new_end = std::remove_if(values.begin(), values.end(),
[](int n) { return n < 0; });
values.erase(new_end, values.end());
// C++20 container convenience:
std::erase_if(values, [](int n) { return n < 0; });remove_if does not erase container elements; it moves retained values forward and returns the logical end. Using only the first line leaves a valid but unspecified tail.
Sorting, Comparators and Binary Search
std::sort(values.begin(), values.end());
const bool has_75 = std::binary_search(values.begin(), values.end(), 75);
auto first_75 = std::lower_bound(values.begin(), values.end(), 75);
auto after_75 = std::upper_bound(values.begin(), values.end(), 75);| Algorithm | Purpose |
|---|---|
sort | Order range; equal order not preserved |
stable_sort | Preserve relative order of equivalent elements |
partial_sort | Sort the first selected part |
nth_element | Place nth element as in sorted order; sides partitioned |
lower_bound | First position not ordered before value |
equal_range | Range of equivalent values |
A comparator must impose strict weak ordering. Use a < b, not a <= b. Binary-search algorithms require a range partitioned according to a compatible ordering; calling them on arbitrary unsorted data violates their precondition.
std::sort(students.begin(), students.end(),
[](const Student& a, const Student& b) {
if (a.mark != b.mark) return a.mark > b.mark;
return a.name < b.name;
});Numeric Algorithms and Type Safety
#include <numeric>
const long long total = std::accumulate(values.begin(), values.end(), 0LL);
std::vector<int> ids(5);
std::iota(ids.begin(), ids.end(), 101); // 101 102 103 104 105The initial value in accumulate determines the accumulation type. Using 0 accumulates as int; use 0LL for a wider integer sum or 0.0 for floating point when appropriate.
| Algorithm | Use |
|---|---|
accumulate | Fold values from an initial value |
iota | Fill with increasing values |
inner_product | Pairwise products and sum/generalized fold |
partial_sum | Running totals |
adjacent_difference | Differences between neighbors |
reduce | Reduction that may reorder operations |
reduce for accumulate when operation order is semantically required.Complete Student-Score Analysis with Output
#include <algorithm>
#include <functional>
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> scores{64, 91, 75, 52, 88};
const int total = std::accumulate(scores.begin(), scores.end(), 0);
const auto passed = std::count_if(scores.begin(), scores.end(),
[](int score) { return score >= 75; });
std::sort(scores.begin(), scores.end(), std::greater<>{});
std::cout << "Descending:";
for (int score : scores) std::cout << ' ' << score;
std::cout << "\nPass count: " << passed
<< "\nAverage: " << total / static_cast<double>(scores.size());
}Total is 370, so the floating-point average is exactly 74 for this dataset. The comparator orders descending, and the pass predicate includes 75.
Common Mistakes, Practice and Review
| Mistake | Correction |
|---|---|
| binary_search on unsorted input | Establish compatible partition/order first |
| Using sort on list | Use list::sort or proper container |
| Dereferencing returned end | Compare with end before access |
| Destination has no space | Resize or use back_inserter |
| remove expected to shrink vector | Erase returned tail |
| Comparator uses <= | Strict weak ordering |
| Wrong accumulate initial type | Choose 0LL/0.0 intentionally |
| Mutating range inside predicate | Keep callback valid and stable |
Practice: sort Student records by two keys, find first failing mark, remove invalid scores, calculate running totals, obtain top three with partial_sort, and compare classic algorithms with C++20 ranges.
- Correct header?
- Valid half-open range?
- Iterator category sufficient?
- Ordering precondition satisfied?
- Comparator/predicate valid?
- Output destination large enough?
- Returned iterator checked?
- Numeric result type deliberate?
Authoritative References
- C++ Working Draft: Algorithms Library
- C++ Working Draft: Non-modifying Algorithms
- C++ Working Draft: Sorting and Related Operations
Iterator requirements, ordering preconditions and algorithm behavior were checked against the current working draft. Practice them with the complete vector tutorial and sorting/searching lesson.
Frequently Asked Questions
What are STL algorithms in C++?
Why do most algorithms use [first, last)?
Can std::sort be used with std::list?
Must data be sorted before binary_search or lower_bound?
What is the erase-remove idiom?
STL Algorithm Model
Container elements own करता है, iterators range बताते हैं और algorithm operation करता है। इससे same find/count_if कई suitable containers पर reusable होता है।
std::vector<int> values{7,2,9,4};
std::sort(values.begin(),values.end());| Family | Examples |
|---|---|
| Queries | find, count, all_of |
| Transform | copy, transform, replace |
| Reorder | reverse, rotate, shuffle |
| Sort/search | sort, lower_bound |
| Numeric | accumulate, iota |
Most algorithms के लिए <algorithm>, numeric के लिए <numeric> direct include करें। STL guide देखें।
Ranges और Iterator Requirements
[first,last) first include और last exclude करती है; end को dereference न करें।
| Algorithm | Iterator |
|---|---|
| find/count | Input |
| copy | Readable + writable output |
| reverse | Bidirectional |
| sort | Random access |
इसलिए std::sort vector पर चलता है, list पर नहीं। C++20 range algorithms whole range और projection ले सकते हैं:
std::ranges::sort(students,std::greater{},&Student::mark);Lazy views source को refer कर सकती हैं; source lifetime पर्याप्त हो। iterators पढ़ें।
Search, Count और Predicates
auto found=std::find(values.begin(),values.end(),9);
if(found!=values.end()) std::cout<<*found;
auto evens=std::count_if(values.begin(),values.end(),
[](int n){return n%2==0;});
bool positive=std::all_of(values.begin(),values.end(),
[](int n){return n>0;});- find/find_if first match या end।
- count/count_if match count।
- all_of सभी, any_of कोई एक, none_of कोई नहीं।
- mismatch first different pair।
Predicate range invalidate न करे; simple, stable lambda रखें।
Transform, Copy और Remove
std::vector<int> doubled(values.size());
std::transform(values.begin(),values.end(),doubled.begin(),
[](int n){return n*2;});
std::vector<int> result;
std::copy_if(values.begin(),values.end(),
std::back_inserter(result),[](int n){return n>=0;});Destination में space हो या insertion iterator लें। Erase-remove:
auto end=std::remove_if(values.begin(),values.end(),
[](int n){return n<0;});
values.erase(end,values.end());
// C++20: std::erase_if(values,predicate);remove_if vector size नहीं घटाता; logical end देता है।
Sorting और Binary Search
std::sort(values.begin(),values.end());
bool found=std::binary_search(values.begin(),values.end(),75);
auto first=std::lower_bound(values.begin(),values.end(),75);- sort equal order preserve नहीं करता।
- stable_sort equivalent order preserve करता है।
- partial_sort selected first part sort करता है।
- nth_element nth को sorted position पर रखता है।
- lower/upper_bound equivalent range की boundaries देते हैं।
Comparator strict weak ordering दे; <= गलत। Binary search के लिए compatible ordering/partition जरूरी है।
Numeric Algorithms और Types
long long total=std::accumulate(values.begin(),values.end(),0LL);
std::vector<int> ids(5);
std::iota(ids.begin(),ids.end(),101);accumulate का initial value result type तय करता है: large integer sum में 0LL और floating case में 0.0 सोचकर चुनें।
| Algorithm | Use |
|---|---|
| accumulate | Fold/sum |
| iota | Increasing fill |
| inner_product | Pairwise fold |
| partial_sum | Running totals |
| reduce | May reorder operations |
Complete Score Analysis और Output
std::vector<int> scores{64,91,75,52,88};
int total=std::accumulate(scores.begin(),scores.end(),0);
auto passed=std::count_if(scores.begin(),scores.end(),
[](int s){return s>=75;});
std::sort(scores.begin(),scores.end(),std::greater<>{});Total 370 है। Pass predicate 75 include करता और comparator descending order देता है।
Mistakes, Practice और Review
| Mistake | Correction |
|---|---|
| Unsorted binary search | Compatible order |
| list पर std::sort | list::sort |
| Returned end dereference | Check first |
| Destination no space | Resize/back_inserter |
| remove shrinks vector | Erase tail |
| Comparator <= | Strict weak order |
| Initial type wrong | 0LL/0.0 |
Practice: Student two-key sort, first failing mark, invalid score removal, running totals, top three और ranges comparison।
- Header?
- Valid range?
- Iterator capability?
- Precondition?
- Comparator?
- Destination?
- Return checked?
- Numeric type?
Authoritative संदर्भ
Requirements और preconditions current draft से verified हैं। vector तथा sorting/searching पर practice करें।