SrcForge

Lesson 53

STL Algorithms and Iterators (part 2)

Covers std::sort, std::for_each, std::count, std::count_if, std::find_if, std::reverse, std::transform, std::copy, std::remove_if, reverse iterators, and const iterators.

Lesson content

Common STL algorithms

The C++ Standard Library provides dozens of algorithms. The list below covers some of the ones you'll use most frequently, all found in the <algorithm> header.

  • std::sort – sort elements
  • std::find – find a value
  • std::find_if – find using a condition
  • std::count – count occurrences
  • std::count_if – count matching elements
  • std::for_each – apply an operation to every element
  • std::reverse – reverse the order of elements
  • std::copy – copy elements
  • std::transform – modify or convert elements
  • std::remove_if – remove elements matching a condition

std::sort

std::sort() arranges elements in ascending order by default.

Example 4: Sorting a vector

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> numbers =
    {
        9, 2, 6, 1, 5
    };

    std::sort(
        numbers.begin(),
        numbers.end()
    );

    for (int value : numbers)
    {
        std::cout << value << " ";
    }

    return 0;
}

// Output: 1 2 5 6 9

You can sort in descending order using a lambda expression as a custom comparator.

std::sort(numbers.begin(), numbers.end(),
          [](int a, int b)
          {
              return a > b;
          });

std::for_each

std::for_each() executes a function or lambda for every element in a range.

Example 5: Printing elements

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> values =
    {
        3, 6, 9, 12
    };

    std::for_each(
        values.begin(),
        values.end(),

        [](int value)
        {
            std::cout << value << " ";
        }
    );

    return 0;
}

// Output: 3 6 9 12

std::count

std::count() counts how many times a value appears.

Example 6: Counting values

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> numbers =
    {
        1, 2, 2, 3, 2, 4
    };

    int total = std::count(
        numbers.begin(),
        numbers.end(),
        2
    );

    std::cout << total;

    return 0;
}

// Output: 3

std::count_if

std::count_if() counts elements that satisfy a condition.

Example 7: Count even numbers

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> numbers =
    {
        10, 15, 20, 21, 30
    };

    int evenCount = std::count_if(
        numbers.begin(),
        numbers.end(),

        [](int value)
        {
            return value % 2 == 0;
        }
    );

    std::cout << evenCount;

    return 0;
}

// Output: 3

std::find_if

std::find_if() searches using a condition instead of an exact value.

Example 8: Find the first number greater than 50

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> marks =
    {
        35, 42, 76, 81, 90
    };

    auto result = std::find_if(
        marks.begin(),
        marks.end(),

        [](int mark)
        {
            return mark > 50;
        }
    );

    if (result != marks.end())
    {
        std::cout << *result;
    }

    return 0;
}

// Output: 76

std::reverse

std::reverse() reverses the order of elements.

Example 9: Reverse a vector

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> values =
    {
        1, 2, 3, 4, 5
    };

    std::reverse(
        values.begin(),
        values.end()
    );

    for (int value : values)
    {
        std::cout << value << " ";
    }

    return 0;
}

// Output: 5 4 3 2 1

std::transform

std::transform() applies a function to each element and stores the result.

Example 10: Square every number

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> numbers =
    {
        1, 2, 3, 4
    };

    std::transform(
        numbers.begin(),
        numbers.end(),
        numbers.begin(),

        [](int value)
        {
            return value * value;
        }
    );

    for (int value : numbers)
    {
        std::cout << value << " ";
    }

    return 0;
}

// Output: 1 4 9 16

std::copy

std::copy() copies elements from one container to another.

Example 11: Copy a vector

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> source =
    {
        10, 20, 30
    };

    std::vector<int> destination(3);

    std::copy(
        source.begin(),
        source.end(),
        destination.begin()
    );

    for (int value : destination)
    {
        std::cout << value << " ";
    }

    return 0;
}

// Output: 10 20 30

std::remove_if

std::remove_if() removes elements matching a condition. Note that std::remove_if doesn't actually erase elements from the container—it moves the elements to keep and returns an iterator to the new logical end. You typically follow it with the container's erase() method, known as the erase-remove idiom.

Example 12: Remove even numbers

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> values =
    {
        1, 2, 3, 4, 5, 6
    };

    values.erase(
        std::remove_if(
            values.begin(),
            values.end(),

            [](int value)
            {
                return value % 2 == 0;
            }
        ),
        values.end()
    );

    for (int value : values)
    {
        std::cout << value << " ";
    }

    return 0;
}

// Output: 1 3 5

Reverse iterators

A reverse iterator traverses a container from the last element to the first. rbegin() points to the last element, and rend() points before the first element.

for (auto it = numbers.rbegin();
     it != numbers.rend();
     ++it)
{
    std::cout << *it << " ";
}

// Output: 5 4 3 2 1

Constant iterators (const_iterator)

A const_iterator allows you to read elements but prevents modification. This is useful when you want to ensure your code doesn't accidentally modify container elements.

std::vector<int>::const_iterator it;

// Or, more commonly:
auto it = values.cbegin();

Example: Sorting student records

#include <iostream>
#include <vector>
#include <algorithm>

struct Student
{
    std::string name;
    int marks;
};

int main()
{
    std::vector<Student> students =
    {
        {"Alice", 78},
        {"Bob", 92},
        {"Charlie", 65}
    };

    std::sort(
        students.begin(),
        students.end(),

        [](const Student& a, const Student& b)
        {
            return a.marks > b.marks;
        }
    );

    for (const auto& student : students)
    {
        std::cout << student.name
                  << " : "
                  << student.marks
                  << '\n';
    }

    return 0;
}

// Output:
// Bob : 92
// Alice : 78
// Charlie : 65

This pattern is commonly used in ranking systems, report cards, leaderboards, and analytics applications.