The C++ Standard Template Library provides algorithms for functions that are commonly needed in everyday scenarios, and for commonly used containers.
Now, I’m sure you’re a gr8 coder and all and could write your own functions, but you should probably use the Standard Library’s functions whenever possible. They’re very efficient, both memory and space-wise, especially if you use STL containers.
Base Code and C++ version
For the sake of testing this code, we’ll specify a very basic C++ file that our code would run in. Note that we include vector, because that’s the container the examples will use, we’re including iostream for cout, and we including algorithm for the actual STL algorithms.
main.cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
// INSERT STD:ALGORITHM EXAMPLE CODE HERE
return 0;
}
We’ll use a simple makefile to compile and run, specifying C++11.
makefile
all:
g++ main.cpp -std=c++11 -o run
./run
And so to actually run this code, in a UNIX operating system, in the terminal, simply type make in the directory where you're makefile and main.cpp are.
Figure Something Out About Data
Need to do something with the data in your container? Look here.
all_of
Check if every element in the range satisfies the condition.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda function that does something with the element of the container.
Returns a bool. True if all elements satisfy the condition, false otherwise.
std::vector<int> v{ 5, 3, 7, 9, 4 };
auto lambda = [](int i) { return i > 1; };
bool allGreaterThanOne = std::all_of(v.begin(), v.end(), lambda); // true
any_of
Check if any element in the range satisfies the condition.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda function that does something with the element of the container.
Returns a bool. True if any element satisfies the condition, false otherwise.
std::vector<int> v{ 5, 3, 7, 9, 4 };
auto lambda = [](int i) { return i > 8; };
bool anyGreaterThanEight = std::any_of(v.begin(), v.end(), lambda); // true
none_of
Check if none of the elements in the range satisfies the condition.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range, and a lambda function that does something with the element of the container.
Returns a bool. True if all elements fail the condition, false if any element passes the condition.
std::vector<int> v{ 5, 3, 7, 9, 4 };
auto lambda = [](int i) { return i > 10; };
bool noneGreaterThanTen = std::none_of(v.begin(), v.end(), lambda); // true
for_each
Does something for each item in a range.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda function that does something with the element of the container.
Returns void.
std::vector<int> v{ 5, 3, 7, 2, 1 };
auto lambda = [](int i) { std::cout << i << " "; };
std::for_each(v.begin(), v.end(), lambda); // Prints each element in the container.
find
Find an item in a given range.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and an item that you want to find.
Returns an iterator to the first element in the range that is equal to the item we specified.
std::vector<int> v{ 5, 3, 7, 9, 4 };
std::vector<int>::iterator it = std::find(v.begin(), v.end(), 3);
find_if
Find the first item that satisfies a condition.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda function that returns a bool.
Returns an iterator to the first element in the range that satisfies the lambda’s condition.
std::vector<int> v{ 5, 3, 7, 9, 4 };
auto lambda = [](int i) { return i > 6; };
std::vector<int>::iterator it = std::find_if(v.begin(), v.end(), lambda);
int firstElementGreaterThanSix = *it; // 7
find_if_not
Find the first item that does not satisfy a condition.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda function that returns a bool.
Returns an iterator to the first element in the range that does not satisfy the lambda’s condition.
std::vector<int> v{ 5, 3, 7, 9, 4 };
auto lambda = [](int i) { return i > 6; };
std::vector<int>::iterator it = std::find_if_not(v.begin(), v.end(), lambda);
int firstElementLessThanSix = *it; // 5
find_end
For a range, find the last occurrence of a sequence in that range. (Ex. Get the last “oo” in “moo_cookies”.)
Pass in an iterator to the beginning of the first range, and an iterator to the end of the first range, and an iterator to the beginning of the sequence, and an iterator to the end of the sequence,
Returns an iterator to the first item of the sequence.
std::string s = "moo_cookies";
std::string t = "oo";
std::string::iterator it = std::find_end(s.begin(), s.end(), t.begin(), t.end());
// Points to the 'o' after the 'c'
find_first_of
For a range, find the first occurrence of a sequence in that range. (Ex. Get the first “oo” in “moo_cookies”.)
Pass in an iterator to the beginning of the first range, and an iterator to the end of the first range, and an iterator to the beginning of the sequence, and an iterator to the end of the sequence,
Returns an iterator to the first item of the sequence.
std::string s = "moo_cookies";
std::string t = "oo";
std::string::iterator it = std::find_first_of(s.begin(), s.end(), t.begin(), t.end());
// Points to the 'o' after the 'm
adjacent_find
Find the first occurrence of two consecutive elements that match in a range. (Ex. The “cc” in “accent”.)
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns an iterator to the first item in the match.
std::string s = "accent";
std::string::iterator it = std::adjacent_find(s.begin(), s.end()); // Points to the first 'c'
count
Count the number of times an item appears in the range.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and the item we want to count.
Returns an integer.
std::vector<int> v{ 5, 3, 7, 9, 3, 4 };
int countOfThree = std::count(v.begin(), v.end(), 3); // 2
count_if
Count the number of occurrences satisfying the lambda function.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda function that returns true or false.
Returns an integer.
std::vector<int> v{ 5, 3, 7, 2, 1 };
auto lambda = [](int i) { return i > 2; };
int count = count_if(v.begin(), v.end(), lambda);
mismatch
Finds the first occurrence where two rangers differ.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and an iterator to the beginning of the second range.
Returns a pair of iterators to the positions where the ranges occur.
std::vector<int> v1{ 5, 3, 7, 9 };
std::vector<int> v2{ 5, 3, 2, 9 };
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> p = std::mismatch(v1.begin(), v1.end(), v2.begin());
int element1 = *p.first; // 7
int element2 = *p.second; // 2
equal
Check if the elements in the two ranges are equal.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and an iterator to the beginning of the second range.
Returns a bool. True if the elements are equal, false otherwise.
std::vector<int> v1{ 5, 4, 6 };
std::vector<int> v2{ 5, 4, 6 };
bool isEqual = std::equal(v1.begin(), v1.end(), v2.begin()); // true
is_permutation
Check if a range is a permutation of another.
A “permutation” is if the items in one range can be rearranged to form the other range. (Ex. “dog” can be rearranged to form “god”.)
Pass in an iterator to the beginning of the range, and an iterator to the end of the range, and an iterator to the beginning of the second range.
Returns a bool. True if the elements are permutations, false otherwise.
std::vector<char> v1{ 'g', 'o', 'd' };
std::vector<char> v2{ 'd', 'o', 'g' };
bool isPermutation = std::is_permutation(v1.begin(), v1.end(), v2.begin()); // true
search
Check if a range contains a certain sequence. (Ex. Does “this” contain “is”?)
Pass in an iterator to the beginning of the first range, and an iterator to the end of the first range, and an iterator to the beginning of the second range (sequence), and an iterator to the end of the second range (sequence).
Returns an iterator to the first item in the range that begins the sequence.
std::vector<char> v1{ 't', 'h', 'i', 's' };
std::vector<char> v2{ 'i', 's' };
std::vector<char>::iterator it = std::search(v1.begin(), v1.end(), v2.begin(), v2.end());
// Points to the 'i' in v1
search_n
Search a range for a certain number of a specific item. (Ex. Find two ‘e’s in a row in the word ‘esteem’.)
Pass in an iterator to the beginning of the range, and an iterator to the end of the range, and the count of the number of the item we need to find, and the item we’re trying to find.
Returns an iterator to the first item in the range that begins the sequence.
std::vector<char> v{ 'e', 's', 't', 'e', 'e', 'm' };
std::vector<char>::iterator it = std::search_n(v.begin(), v.end(), 2, 'e');
// Points to the 'e' after the 't'.
lexicographical_compare
Lexographically compare two items to find out which is ‘smaller’.
Pass in an iterator to the beginning of the first range, and an iterator to the end of the first range, an iterator to the beginning of the second range, and an iterator to the end of the second range.
Returns a bool. True if the first range is lexographically less than the second range.
std::string s = "abc";
std::string t = "def";
bool sIsSmaller = std::lexicographical_compare(s.begin(), s.end(), t.begin(), t.end()); // true
Modify/Copy A Range
A range is going to be edited or copied.
copy
Copy the elements from one range into another.
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, and an iterator to the beginning of the copy range.
Returns an iterator to the element after the last one we wrote to in the copy range.
std::vector<int> v1{ 1, 2, 3, 4 };
std::vector<int> v2(4);
std::vector<int>::iterator it = std::copy(v1.begin(), v1.end(), v2.begin());
// v2 is { 1 2 3 4 }
// 'it' points to the element after 4 in v2.
copy_n
Copy the first n elements from one range into another.
Pass in an iterator to the beginning of the first range, an int representing how many elements to copy, and an iterator to the beginning of the copy range.
Returns an iterator to the element after the last one we wrote to in the copy range.
std::vector<int> v1{ 1, 2, 3, 4 };
std::vector<int> v2(2);
std::vector<int>::iterator it = std::copy_n(v1.begin(), 2, v2.begin());
// v2 is { 1 2 }
// "it" points to the element after 2 in v2.
copy_if
Copy elements from one range into another if the condition we specify is met.
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, an iterator to the beginning of the copy range, and a lambda function that returns a bool.
Returns an iterator to the element after the last one we wrote to in the copy range.
std::vector<int> v1{ 1, 2, 3, 4 };
std::vector<int> v2(2);
auto lambdaIsEven = [](int i) { return i % 2 == 0; };
std::vector<int>::iterator it = std::copy_if(v1.begin(), v1.end(), v2.begin(), lambdaIsEven);
// v2 is { 2 4 }
// "it" points to the element after 4 in v2.
copy_backward
Copy the elements from one range into another, starting from the back elements and going to the front.
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, and an iterator to the end of the copy range.
Returns an iterator to the last element we wrote to in the copy range (which is the beginning of the copy range).
std::vector<int> v1{ 1, 2, 3, 4 };
std::vector<int> v2(4);
std::vector<int>::iterator it = std::copy_backward(v1.begin(), v1.end(), v2.end());
// v2 is { 1 2 3 4 }
// "it" points to the 1 in v2.
move
Move the elements from one range into another. The elements in the original range are valid, but may not be what they were before the move.
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, and an iterator to the beginning of the move range.
Returns an iterator to the element after the last one we wrote to in the move range.
std::vector<int> v1{ 1, 2, 3, 4 };
std::vector<int> v2(4);
std::vector<int>::iterator it = std::move(v1.begin(), v1.end(), v2.begin());
// v1 is { 1 2 3 4 } (It just happens to be unchanged.)
// v2 is { 1 2 3 4 }
// 'it' points to the element after 4 in v2.
move_backward
Move the elements from one range into another, starting from the back elements and going to the front. The elements in the original range are valid, but may not be what they were before the move.
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, and an iterator to the end of the move range.
Returns an iterator to the last element we wrote to in the move range (which is the beginning of the move range).
std::vector<int> v1{ 1, 2, 3, 4 };
std::vector<int> v2(4);
std::vector<int>::iterator it = std::move_backward(v1.begin(), v1.end(), v2.end());
// v1 is { 1 2 3 4 } (It just happens to be unchanged.)
// v2 is { 1 2 3 4 }
// 'it' points to the 1 in v2.
swap
Swaps the values of two items.
Pass in the first and the second item.
Returns void.
int a = 5;
int b = 10;
std::swap(a, b); // Now a = 10 and b = 5.
swap_ranges
Given two ranges, swaps the items in them (using the swap function).
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, and an iterator to the beginning of the second range.
Returns an iterator to the element after the last one we wrote to in the second range.
std::vector<int> v1{ 1, 2, 3, 4 };
std::vector<int> v2{ 5, 6, 7, 8 };
std::vector<int>::iterator it = std::swap_ranges(v1.begin(), v1.end(), v2.begin());
// v1 is { 5 6 7 8 }
// v2 is { 1 2 3 4 }
// 'it' points to the element after 4 in v2.
iter_swap
Swap the values that two iterators point too.
Pass in an iterator to the first value, and an iterator to the second value.
Returns void.
std::vector<int> v{ 1, 2, 3, 4, 5 };
std::vector<int>::iterator it1 = v.begin(); // Points to 1
std::vector<int>::iterator it2 = v.end() - 1; // Points to 4
std::iter_swap(it1, it2);
// v is now { 5 2 3 4 1 }
transform
Given one or two ranges, performs an operation on each value of the range and stores that result in another range. (For example, multiply each value in a vector by some number and store it in another vector. Or add each value in two vectors and put that into another vector.)
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, (optionally, an iterator to the beginning of the second range if there is one), and an iterator to the beginning of the resulting range, and a lamba expression that accepts the element type(s) and returns the element type that does the operation we want to want to do on the range(s).
Returns an iterator to the element after the last one we wrote to in the resulting range.
Example with just one range:
std::vector<int> v{ 1, 2, 3, 4, 5 };
std::vector<int> res(5);
auto lambdaAddOne = [](int i) { return i + 1; };
std::vector<int>::iterator it = std::transform(v.begin(), v.end(), res.begin(), lambdaAddOne);
// res is { 2 3 4 5 6 }
Example with two ranges:
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 4, 5, 6 };
std::vector<int> res(3);
auto lambdaMultiply = [](int i, int j) { return i * j; };
std::vector<int>::iterator it = std::transform(v1.begin(), v1.end(), v2.begin(), res.begin(), lambdaMultiply);
// res is { 4 10 18 }
replace
For a range, replaces an old value (that we specify) with a new value (that we specify). (Ex. Replace all 3’s with 7’s.)
Pass in an iterator to the beginning of the range, an iterator to the end of the range, the old value, and the new value.
Returns void.
std::vector<int> v{ 1, 2, 3, 4, 3, 5 };
std::replace(v.begin(), v.end(), 3, 7);
// res is now { 1 2 7 4 7 5 }
replace_if
For a range, replaces an element that passes a certain condition with a new value (that we specify). (Ex. Replace all negative elements with a 0.)
Pass in an iterator to the beginning of the range, an iterator to the end of the range, a lambda expression that returns a bool, and the new value.
Returns void.
std::vector<int> v{ 1, 2, -3, 4, -5 };
auto lambdaIsNegative = [](int i) { return i < 0; };
std::replace_if(v.begin(), v.end(), lambdaIsNegative, 0);
// res is now { 1 2 0 4 0 }
replace_copy
For a range, copies the elements into another range, and replaces any element (that we specify) with a new value (that we specify) for the new range. Doesn’t change the old range. (Ex. Replace all 3’s with 7’s.)
Pass in an iterator to the beginning of the range, an iterator to the end of the range, an iterator to the beginning of the new range, the old value, and the new value.
Returns an iterator to the element after the last one we wrote to in the resulting range.
std::vector<int> v{ 1, 2, 3, 4, 3, 5 };
std::vector<int> res(6);
//auto lambdaIsNegative = [](int i) { return i < 0; };
std::vector<int>::iterator it = std::replace_copy(v.begin(), v.end(), res.begin(), 3, 7);
// v is still { 1 2 3 4 3 5 }
// res is now { 1 2 7 4 7 5 }
// 'it' points to the element after 5 in res.
replace_copy_if
For a range, copies the elements into another range, and replaces any element that passes a certain condition with a different value (that we specify) for the new range. Doesn’t change the old range. (Ex. Replace all negative elements with a 0.)
Pass in an iterator to the beginning of the range, an iterator to the end of the range, an iterator to the beginning of the new range, a lambda expression that returns a bool, and the new value.
Returns an iterator to the element after the last one we wrote to in the resulting range.
std::vector<int> v{ 1, 2, -3, 4, -5 };
std::vector<int> res(5);
auto lambdaIsNegative = [](int i) { return i < 0; };
std::vector<int>::iterator it = std::replace_copy_if(v.begin(), v.end(), res.begin(), lambdaIsNegative, 0);
// v is still { 1 2 -3 4 -5 }
// res is now { 1 2 0 4 0 }
// 'it' points to the element after the second 0 in res.
fill
For a range, fill every element with an item (that we specify). (Ex. Fill a range with all 7s.)
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and the value that we want to fill it with.
Returns void.
std::vector<int> v{ 1, 2, 3, 4, 5 };
std::fill(v.begin(), v.end(), 7);
// v is now { 7 7 7 7 7 }
fill_n
For a range, fill every element with an item (that we specify). (Ex. Fill the first 3 elements of a range with 7s.)
Pass in an iterator to the beginning of the range,the number of elements we want to fill, and the value that we want to fill it with.
Returns an iterator to the element after the last one we wrote to.
std::vector<int> v{ 1, 2, 3, 4, 5 };
std::fill_n(v.begin(), 3, 7); // Fill the first 3, only.
// v is now { 7 7 7 4 5 }
generate
For a range, assigns each element with a value generated by a function (that we specify). (Ex. Use a random number generator function to determine what to assign each element.)
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a function (that accepts no parameters) that returns the type of the range.
Returns void.
std::vector<int> v{ 1, 2, 3, 4, 5 };
auto lambdaReturnNine = []() { return 9; };
std::generate(v.begin(), v.end(), lambdaReturnNine);
// v is now { 9 9 9 9 9 }
generate_n
For a range, assigns each element with a value generated by a function (that we specify) for the first n elements. (Ex. Use a random number generator function to determine what to assign each element for the first 3 elements.)
Pass in an iterator to the beginning of the range, the number of elements we want assign to, and a function (that accepts no parameters) that returns the type of the range.
Returns an iterator to the element after the last one we wrote to.
std::vector<int> v{ 1, 2, 3, 4, 5 };
auto lambdaReturnNine = []() { return 9; };
std::generate_n(v.begin(), 3, lambdaReturnNine);
// v is now { 9 9 9 4 5 }
remove
For a range, removes any element that has a certain value (that you specify). This is done by moving a valid element into the removed element’s spot. (The container size does not change.) You’ll know where the updated range ends by checking where the returned iterator is. Order is not preserved, and the extra elements at the end of the range are in some valid state.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and the value to be removed.
Returns an iterator after the last valid element in the range.
std::vector<int> v{ 1, 2, 3, 4, 5 };
std::vector<int>::iterator it = std::remove(v.begin(), v.end(), 2);
// v is now { 1 3 4 5 5 }
// 'it' points to the element after the first 5 in v.
remove_if
For a range, removes any element that passes a certain condition (that you specify). This is done by moving a valid element into the removed element’s spot. (The container size does not change.) You’ll know where the updated range ends by checking where the returned iterator is. Order is not preserved, and the extra elements at the end of the range are in some valid state.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda function that returns a bool.
Returns an iterator after the last valid element in the range.
std::vector<int> v{ 1, 2, 3, 4, 5 };
auto lambdaIsOdd = [](int i) { return i % 2 != 0; };
std::vector<int>::iterator it = std::remove_if(v.begin(), v.end(), lambdaIsOdd);
// v is now { 2 4 3 4 5 }
// 'it' points to the element after the first 4 in v.
remove_copy
For a given range, copies each element into a new range, except for elements with a certain value (that you specify). The original range is untouched.
Pass in an iterator to the beginning of the original range, an iterator to the end of the original range, an iterator to the beginning of the copy range, and the value that you want to skip.
Returns an iterator after the last valid element in the copy range.
std::vector<int> v{ 1, 2, 3, 4, 5 };
std::vector<int> res(5);
std::vector<int>::iterator it = std::remove_copy(v.begin(), v.end(), res.begin(), 2);
// v is now { 1 3 4 5 0 } // (The zero is from the initialization.)
// 'it' points to the element after the 5 in res
remove_copy_if
For a given range, copies each element into a new range, except for elements that pass a certain condition (that you specify). The original range is untouched.
Pass in an iterator to the beginning of the original range, an iterator to the end of the original range, an iterator to the beginning of the copy range, and a lambda function that returns a bool.
Returns an iterator after the last valid element in the copy range.
std::vector<int> v{ 1, 2, 3, 4, 5 };
std::vector<int> res(5);
auto lambdaIsOdd = [](int i) { return i % 2 != 0; };
std::vector<int>::iterator it = std::remove_copy_if(v.begin(), v.end(), res.begin(), lambdaIsOdd);
// v is now { 2 4 0 0 0 } // (The zeroes are from the initialization.)
// 'it' points to the element after the 4 in res
unique
For a range, remove consecutive duplicate elements. (Ex. { 2 2 3 3 4 4 4 3 } -> { 2 3 4 3 ? ? ? ? } ) This is done by moving a valid element into the removed element’s spot. (The container size does not change.) You’ll know where the updated range ends by checking where the returned iterator is. Order is not preserved, and the extra elements at the end of the range are in some valid state.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns an iterator after the last valid element in the range.
std::vector<int> v{ 2, 2, 3, 3, 4, 4, 4, 3 };
std::vector<int>::iterator it = std::unique(v.begin(), v.end());
// v is now { 2 3 4 3 4 4 4 3 }
// 'it' points to the element after the second 3 in v.
unique_copy
For a range, copies all elements that don’t have a duplicate neighbor into a new range (that you specify). (Ex. { 2 2 3 3 4 4 4 3 } -> { 2 3 4 3 } ) The original range is untouched.
Pass in an iterator to the beginning of the original range, an iterator to the end of the original range, and an iterator to the beginning of the copy range.
Returns an iterator after the last copied element in the copy range.
std::vector<int> v{ 2, 2, 3, 3, 4, 4, 4, 3 };
std::vector<int> res(8);
std::vector<int>::iterator it = std::unique_copy(v.begin(), v.end(), res.begin());
// v is still { 2 3 4 3 4 4 4 3 }
// res is now { 2 3 4 3 0 0 0 0 } (The zeroes are from initialization.)
// 'it' points to the element after the second 3 in res.
reverse
For a range, reverses the order of the elements. (Ex. { 1 2 3 4 } -> { 4 3 2 1 } .)
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns void.
std::vector<int> v{ 1, 2, 3, 4 };
std::reverse(v.begin(), v.end());
// v is { 4 3 2 1 }
reverse_copy
For a range, copies the elements in verse order into a new range (that you specify). (Ex. { 1 2 3 4 } -> { 4 3 2 1 } .) The original range is untouched.
Pass in an iterator to the beginning of the original range, an iterator to the end of the original range, and an iterator to the beginning of the copy range.
Returns an iterator after the last copied element in the copy range.
std::vector<int> v{ 1, 2, 3, 4 };
std::vector<int> res(4);
std::vector<int>::iterator it = std::reverse_copy(v.begin(), v.end(), res.begin());
// v is { 1 2 3 4 }
// res is { 4 3 2 1 }
// 'it' points to the element after 1 in res
rotate
For a range, rotates the elements (in a circular fashion) so that a specified becomes the new first element, and every other element is shifted over.
Pass in an iterator to the beginning of the range, an iterator to the element we want to be the beginning of the range, and an iterator to the end of the range.
Returns void.
std::vector<int> v{ 1, 2, 3, 4 };
std::vector<int>::iterator it = v.begin() + 2; // Points to 3
std::rotate(v.begin(), it, v.end());
// v is now { 3 4 1 2 }
rotate_copy
For a range, copies the elements into a new range if the elements were rotating (in a circular fashion) so that a specified becomes the new first element, and every other element is shifted over. The original range is untouched.
Pass in an iterator to the beginning of the original range, an iterator to the element we want to be the beginning of the copy range. an iterator to the end of the original range, and an iterator to the beginning of the copy range.
Returns an iterator after the last copied element in the copy range.
std::vector<int> v{ 1, 2, 3, 4 };
std::vector<int> res(4);
std::vector<int>::iterator it1 = v.begin() + 2; // Points to 3
std::vector<int>::iterator it2 = std::rotate_copy(v.begin(), it1, v.end(), res.begin());
// v is still { 1 2 3 4 }
// res is { 3 4 1 2 }
// 'it2' points to the element after 2 in res
random_shuffle
For a range, rearranges the elements randomly. (random_shuffle uses rand() as the random number generator.)
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns void.
std::vector<int> v{ 1, 2, 3, 4 };
std::random_shuffle(v.begin(), v.end());
// v is { 1 4 2 3 }
shuffle
For a range, rearranges the elements randomly using a uniform random number generator (that you must provide).
Pass in an iterator to the beginning of the range, and an iterator to the end of the range, and a random number generator.
Returns void.
You should really be using random or some other library to provide a random number generator. Since the code example isn’t simple, I’ll just provide a link to cplusplus.com’s shuffle page for sample code..
Partitioned
Operate on partioned data, which is split in half based on a certain condition.
is_partitioned
Check if the data in a range is partitioned according to a condition you specify. (Ex. Are the odd elements separated from the even elements?)
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda that returns a bool.
Returns a bool. True if the data is in the beginning all return true and the data afterward all return false. Returns false otherwise.
std::vector<int> v{ 5, 3, 1, 8, 4, 6 };
auto lambdaIsOdd = [](int i) { return i % 2 != 0; };
bool isPartitioned = std::is_partitioned(v.begin(), v.end(), lambdaIsOdd); // true
Note that if the data is all false and then all true, is_partitioned will return false. Make sure your lambda will return “true” for the front data. For example..
std::vector<int> v{ 5, 3, 1, 8, 4, 6 };
auto lambdaIsEven = [](int i) { return i % 2 == 0; };
bool isPartitioned = std::is_partitioned(v.begin(), v.end(), lambdaIsEven); // false
isPartitioned is false even though the data is clearly partitioned. That’s because the first partition returns false and the second partition returns true.
partition
Rearranges the elements in a range so that the first group returns true for the condition you specify. (Ex. Move all odd elements to the front.)
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda that returns a bool.
Returns an iterator to the first element of the second partition.
std::vector<int> v{ 1, 2, 3, 4, 5, 6, 7 };
auto lambdaIsOdd = [](int i) { return i % 2 != 0; };
std::vector<int>::iterator it = std::partition(v.begin(), v.end(), lambdaIsOdd);
// v is now { 1 7 3 5 4 6 2 }
stable_partition
Rearranges the elements in a range so that the first group returns true for the condition you specify. (Ex. Move all odd elements to the front.) Order is preserved.
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda that returns a bool.
Returns an iterator to the first element of the second partition.
std::vector<int> v{ 1, 2, 3, 4, 5, 6, 7 };
auto lambdaIsOdd = [](int i) { return i % 2 != 0; };
std::vector<int>::iterator it = std::stable_partition(v.begin(), v.end(), lambdaIsOdd);
// v is now { 1 3 5 7 2 4 6 }
partition_copy
For a range, copies the data which is true for a condition we specify into some range, and copies the data that is false into some other range.
Pass in an iterator to the beginning of the original range, an iterator to the end of the original range, an iterator to the beginning of the “true” range, an iterator to the end of the “false” range, and a lambda that returns a bool.
Returns a pair of iterators to the element after the last entered element for each of the copy ranges.
std::vector<int> v1{ 1, 2, 3, 4, 5, 6, 7 };
std::vector<int> v2(7);
std::vector<int> v3(7);
auto lambdaIsOdd = [](int i) { return i % 2 != 0; };
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> p = std::partition_copy(v1.begin(), v1.end(), v2.begin(), v3.begin(), lambdaIsOdd);
// v2 is now { 1 3 5 7 0 0 0 } (The zeroes are from initialization.)
// v3 is now { 2 4 6 0 0 0 0 } (The zeroes are from initialization.)
partition_point
Get the first element in a partitioned range that returns false for a given condition. (The element that begins the partition.)
Pass in an iterator to the beginning of the range, an iterator to the end of the range, and a lambda that returns a bool.
Returns an iterator to the element.
std::vector<int> v{ 5, 3, 1, 8, 4, 6 };
auto lambdaIsOdd = [](int i) { return i % 2 != 0; };
std::vector<int>::iterator it = std::partition_point(v.begin(), v.end(), lambdaIsOdd);
// Points to 8
Sorting data.
sort
Sort the elements in a container for the given range.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns void.
std::vector<int> v{ 5, 3, 7, 2, 1 };
std::sort(v.begin(), v.end());
// v is now { 1, 2, 3, 5, 7 }.
stable_sort
Sort the elements in a container for the given range, but the sort is stable.
A “stable” sort means that for equal elements, an element that was ahead of another before the sort will be ahead after the sort.
std::vector<int> v{ 5, 3, 7, 3, 2, 1 }; // { 5, 3a, 7, 3b, 2, 1 }
std::stable_sort(v.begin(), v.end());
// v is now { 1, 2, 3a, 3b, 5, 7 }
Stable sort is best used for objects.
partial_sort
For a position in a range, make sure all the elements from the beginning of the range up to that position are the smallest elements in the range and are sorted. (The rest of the elements (which are up to the position until the end of the range) aren’t in any specific order.)
Pass in an iterator to the beginning of the range, and an iterator to the end of the range, and an iterator to the position we want to partially sort for.
Returns void.
std::vector<int> v{ 5, 1, 3, 7, 6, 2, 9, 4 };
std::vector<int>::iterator it = v.begin() + 3;
std::partial_sort(v.begin(), v.end(), it);
// v ends up as { 1, 2, 3, 4, 5, 6, 7, 9}
In the code example, v ends up fully sorted, but only the first three elements are guaranteed to be sorted.
partial_sort_copy
Copies the items from a range into a second range, in sorted order.
Pass in an iterator to the beginning of the first range, and an iterator to the end of the first range, and an iterator to the beginning of the range we want to copy into, and an iterator to the end of the range we want to copy into,
Returns an iterator to the item after where we finished writing to in the copy range.
std::vector<int> v1{ 5, 1, 3, 7, 6, 2, 9, 4 };
std::vector<int> v2(6); // Initialize v2 with 6 elements.
std::vector<int>::iterator itStart = v1.begin() + 1;
std::vector<int>::iterator itEnd = v1.end() - 1;
std::partial_sort_copy(itStart, itEnd, v2.begin(), v2.end());
// v2 ends up as { 1, 2, 3, 6, 7, 9}
// 5 and 4 are skipped since they aren't in range. v2 is in sorted order.
is_sorted
Check whether a given range is sorted.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns a bool. True if the range is sorted, false if it’s not sorted.
std::vector<int> v{ 5, 3, 7, 2, 1 };
bool isSorted = std::is_sorted(v.begin(), v.end()); // false
is_sort_until
Finds the first element in a range that isn’t sorted.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns an iterator to the first unsorted element.
std::vector<int> v{ 2, 3, 4, 1, 5 };
std::vector<int>::iterator it = std::is_sorted_until(v.begin(), v.end());
// Points to the 1
nth_element
For the position that you specify in a range, places the element at that position that would be there if the range was sorted. (“What would the nth element be if this range was sorted” without actually sorting the entire range.)
Pass in an iterator to the beginning of the range, an iterator to the position we want to find out about, and an iterator to the end of the range.
Returns void. (The range is edited, though.)
std::vector<int> v{ 5, 3, 7, 9, 4 };
// v sorted would be { 3, 4, 5, 7, 9 }
std::vector<int>::iterator it = v.begin() + 1; // 2nd element in v.
std::nth_element(v.begin(), it, v.end());
int element = v[1]; // 4
Binary Search
These algorithms are about binary searching O(log N) a sorted range for a value.
lower_bound
Returns an iterator for the lower bound of an element in a range.
“Lower bound” means the first element that is not less than the element we’re searching for.
For example, for vector [3, 3, 4, 4, 4, 5, 7], lower_bound(4) points to the very first 4 (at index 2).
lower_bound(6) points to 7, since that’s the first element not less than 6.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range, and the element you want to search for.
Returns an iterator to the element. (Or to the container’s end if the element doesn’t exist.)
std::vector<int> v{ 3, 3, 4, 4, 4, 5, 7 };
std::vector<int>::iterator it = std::lower_bound(v.begin(), v.end(), 4);
int index = it - v.begin(); // 2
upper_bound
Returns an iterator for the upper bound of an element in a range.
“Upper bound” means the first element that is greater than the element we’re searching for.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range, and the element you want to search for.
Returns an iterator to the element. (Or to the container’s end if the element doesn’t exist.)
std::vector<int> v{ 3, 3, 4, 4, 4, 5, 7 };
std::vector<int>::iterator it = std::upper_bound(v.begin(), v.end(), 4);
int index = it - v.begin(); // 5
equal_range
Finds the starting index and ending index for an element in a range. (Meaning if we have duplicates of an item in a container, and we want to find out the range of where those items are.)
Pass in an iterator to the beginning of the range, and an iterator to the end of the range, and the element you want to search for.
Returns an pair of iterators of the element type.
std::vector<int> v{ 3, 3, 4, 4, 4, 5, 7 };
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> p = std::equal_range(v.begin(), v.end(), 4);
std::vector<int>::iterator startIterator = p.first;
std::vector<int>::iterator endIterator = p.second;
int startIndex = startIterator - v.begin(); // 2
int endIndex = endIterator - v.begin(); // 5
binary_search
Returns true if an element exists in a sorted range. Returns false otherwise. Does a binary search to find the item.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range, and the element you want to search for.
Returns a bool.
std::vector<int> v{ 5, 3, 7, 2, 1 };
std::sort(v.begin(), v.end());
bool twoExists = std::binary_search(v.begin(), v.end(), 2); // true
Sorted Data Operations
Is your data sorted? If yes, then do these efficient operations on them.
merge
Given two sorted ranges, combine them to form one larger sorted range.
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, an iterator to the beginning of the second range, an iterator to the end of the second range, and an iterator to the beginning of the resulting range that you want to place all of the data into.
Returns an iterator to the end of the resulting range after placing the last item into it.
std::vector<int> v1{ 1, 3, 5, 9 };
std::vector<int> v2{ 2, 4, 6, 7 };
std::vector<int> res(8);
std::vector<int>::iterator it = std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), res.begin());
// res is { 1, 2, 3, 4, 5, 6, 7, 9 }
// 'it' points to the element after 9 in res
inplace_merge
Given two consecutive sorted ranges (in the same container), do an in-place merge to sort the entire range.
Pass in an iterator to the beginning of the first sorted range, an iterator to the beginning of the second sorted range, and an iterator to the end of the second sorted range.
Returns void.
std::vector<int> v{ 6, 7, 8, 1, 2, 3 };
std::inplace_merge(v.begin(), v.begin()+3, v.end());
// v is now { 1, 2, 3, 6, 7, 8 }
includes
Check if a given a sorted range contains a second (sorted) range (that you specify). (Ex. Does “abcmopxyz” contain “mop”?)
Pass in an iterator to the beginning of the first sorted range, an iterator to the end of the first sorted range. an iterator to the beginning of the second sorted range, and an iterator to the second sorted range.
Returns a bool. True if the first range contains the second range, false if it doesn’t.
std::string s = "abcmopxyz";
std::string t = "mop";
bool containsMop = std::includes(s.begin(), s.end(), t.begin(), t.end()); // true
set_union
Given two sorted ranges, creates a new sorted range from the elements that exist in either range. (The union.)
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, an iterator to the beginning of the second range, an iterator to the end of the second range, and an iterator to the beginning of the resulting range that you want to place all of the data into.
Returns an iterator to the element after the last element we placed in the resulting range.
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 1, 1, 2, 4 };
std::vector<int> res(7);
std::vector<int>::iterator it = std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), res.begin());
// res is { 1 1 2 3 4 0 0 } (Zeroes were from the initialization)
// 'it' points to the element after 4 in res.
Notice that there are only two 1’s in the resulting range. set_union will take the maximum number of an element from one range; it won’t just add them.
set_intersection
Given two sorted ranges, created a new sorted range from the elements that exist in both ranges. (The intersection.)
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, an iterator to the beginning of the second range, an iterator to the end of the second range, and an iterator to the beginning of the resulting range that you want to place all of the data into.
Returns an iterator to the element after the last element we placed in the resulting range.
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 1, 1, 2, 4 };
std::vector<int> res(7);
std::vector<int>::iterator it = std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), res.begin());
// res is { 1 2 0 0 0 0 0 } (Zeroes were from the initialization)
// 'it' points to the element after 2 in res.
set_difference
Given two sorted ranges, created a new sorted range from the elements that exist in the first range that don’t exist in the second range. (The difference.)
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, an iterator to the beginning of the second range, an iterator to the end of the second range, and an iterator to the beginning of the resulting range that you want to place all of the data into.
Returns an iterator to the element after the last element we placed in the resulting range.
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 1, 1, 2, 4 };
std::vector<int> res(7);
std::vector<int>::iterator it = std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), res.begin());
// res is { 3 0 0 0 0 0 0 } (Zeroes were from the initialization)
// 'it' points to the element after 3 in res.
set_symmetric_difference
Given two sorted ranges, created a new sorted range from the elements that exist in one of the ranges but doesn’t exist in the other range. (The symmetric difference.)
Pass in an iterator to the beginning of the first range, an iterator to the end of the first range, an iterator to the beginning of the second range, an iterator to the end of the second range, and an iterator to the beginning of the resulting range that you want to place all of the data into.
Returns an iterator to the element after the last element we placed in the resulting range.
std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 1, 1, 2, 4 };
std::vector<int> res(7);
std::vector<int>::iterator it = std::set_symmetric_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), res.begin());
// res is { 1 3 4 0 0 0 0 } (Zeroes were from the initialization)
// 'it' points to the element after 4 in res.
Notice the 1 in res. That’s there because v2 has an extra 1 that v1 does not have.
Heap
Algorithms regarding heap data structures.
A “heap” is a binary tree that always has maximum element as the root node (top of the tree). It’s used in priority queues. (It can also have the min element as the root.)
make_heap
Rearranges the items in a range so that they form a heap.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns void.
std::vector<int> v{ 1, 2, 3, 4 };
std::make_heap(v.begin(), v.end());
// v is now { 4 2 3 1 }
push_heap
If the first elements of a range are a heap, but the last item isn’t, then push_heap will place that last item into its correct position.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns void.
std::vector<int> v{ 4, 2, 3, 1 }; // v is already a heap.
v.push_back(5); // v is no longer a heap.
std::push_heap(v.begin(), v.end());
// v is now { 5 4 2 3 1 }, which is a heap.
pop_heap
Given a range for a heap, places the max element at the end of the range, and rearranges the rest of the elements to be a heap again.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns void.
std::vector<int> v{ 5, 4, 2, 3, 1 }; // v is a heap.
std::pop_heap(v.begin(), v.end());
// v is now { 4 2 3 1 5 }. (The first 4 elements are a heap.)
sort_heap
If a range is a heap, rearrange it into sorted order.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns void.
std::vector<int> v{ 5, 4, 2, 3, 1 }; // v is a heap.
std::sort_heap(v.begin(), v.end());
// v is now { 1 2 3 4 5 }.
is_heap
Check if a range is a heap.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns a bool. True if the range is a heap, false if it’s not a heap.
std::vector<int> v{ 5, 4, 2, 3, 1 }; // v is a heap.
bool isHeap = std::is_heap(v.begin(), v.end()); // true
is_heap_until
Find the first place in a range that makes the range fail to be a heap.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns an iterator to the first element that makes the range fail to be a heap.
std::vector<int> v{ 5, 4, 2, 3, 1, 200 };
std::vector<int>::iterator it = std::is_heap_until(v.begin(), v.end()); // Points to 200
Min and Max
These algorithms are related to finding the minimum/maximum element in a range, or when comparing two items.
min
Compares two items and returns the smaller one.
Pass in two items (ints, for example) as parameters.
Returns the item’s type.
int m = std::min(5, 2); // 2
max
Compares two items and returns the larger one.
Pass in two items (ints, for example) as parameters.
Returns the item’s type.
int m = std::max(5, 2); // 5
minmax
Kind of useless in my opinion. Not even going to post the implementation. see minmax_element for something useful.
min_element
Returns an iterator to the smallest element for a given range.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns an iterator of the type of the collection.
std::vector<int> v{ 5, 3, 7, 2, 1 };
std::vector<int>::iterator it = std::min_element(v.begin(), v.end());
// 'it' points to the 1 in v
max_element
Returns an iterator to the largest element for a given range.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns an iterator of the type of the collection.
std::vector<int> v{ 5, 3, 7, 2, 1 };
std::vector<int>::iterator it = std::max_element(v.begin(), v.end());
// 'it' points to the 7 in v
minmax_element
Returns a pair of iterators to the smallest and the largest elements for a given range. (The smallest is the first item and the largest in the second item.)
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns an std::pair of iterators of type of the collection.
std::vector<int> v{ 5, 3, 7, 2, 1 };
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> p = std::minmax_element (v.begin(), v.end());
int smallest = *p.first; // 1
int largest = *p.second; // 7
Permutations
Permute data into its next transformation.
next_permutation
Rearranges the items in the specified range into the next lexicographically greater permutation.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns a bool. True if the range was transformed, false otherwise (if there was no such possible permutation).
std::string s = "abc";
std::next_permutation(s.begin(), s.end());
// s is now "acb"
prev_permutation
Rearranges the items in the specified range into the previous lexicographically ordered permutation.
Pass in an iterator to the beginning of the range, and an iterator to the end of the range.
Returns a bool. True if the range was transformed, false otherwise (if there was no such possible permutation).
std::string s = "acb";
std::prev_permutation(s.begin(), s.end());
// s is now "abc"
End Notes
The auto the keyword was purposely not used often in this documentation, but use it in your real code.
Note that I say “range” a lot, even though I specifically use vector.begin() and vector.end() most of the time. Remember that your range can be anywhere in the container you want.
Some algorithms also have an overloaded version to provide a custom comparator (for example, stable_sort), but I’ve committed those to keep the examples short.
Pay careful attention to the ordering of the parameters, some are not intuitive. (Ex. nth_element)
References
cplusplus.com’s list of STL algorithms.
Jonathan Boccara’s CppCon Talk about the STL Algorithms.
Written by follow him on the social web or sign up for the email newsletter for your daily dose of how-to guides and video tutorials.
, personal technology columnist and founder of Logical Bee. You canC++
0 Comments:
Post a Comment