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 9You 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 12std::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: 3std::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: 3std::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: 76std::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 1std::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 16std::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 30std::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 5Reverse 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 1Constant 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 : 65This pattern is commonly used in ranking systems, report cards, leaderboards, and analytics applications.