STL Algorithms

Back

Loading concept...

๐Ÿงฐ 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:

  1. Where to start (beginning of your data)
  2. Where to stop (end of your data)
  3. 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);
  1. start = Where to begin (usually .begin())
  2. end = Where to stop (usually .end())
  3. โ€ฆ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! ๐Ÿš€

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.