Chapter 23 - Notes
The <algorithm> header provides a set of generic functions that help manipulate or work with the contents of a container.
The algorithms reduce boilerplate code by helping you:
Count, search, find, copy, and remove elements from a container
Set values in a range of elements to the return value of a generator function, or constant
Sort of partition elements in a range
Insert elements at the correct position in a sorted range
The functions in the <algorithm> header are generic template functions. The pervasive use of iterators ensure that the functions can be used with any containers.
Classification of STL Algorithms
Non-Mutating Algorithms
Algorithms that do not change the order or contents of a container are known as non-mutating algorithms.
Counting algorithms
count()- Find all elements in a range matching a given valuecount_if()- Find all elements in a range matching a supplied predicate
Search algorithms
search()- Search for the first occurrence a subsequencesearch_n()- Searches for the first occurrence ofnnumber of elements of a given value, or those that match a supplied predicate.find()- Searches for the first element in the range that matches a given valuefind_if()- Searches for the first element in a range that matches a given predicatefind_end()- Searches for the last occurrence of a particular subsequencefind_first_of()- Searches for the first instance of any element in a subsequenceadjacent_find()- Searches for two subsequent elements in a collection that are either equal, or match a supplied predicate.
Comparison algorithms
equal()- Compares two elements for equality, optionally using a binary predicatemismatch()- Locates the position of the first difference of two ranges, optionally with a specified binary predicatelexicographical_compare()- Compares elements between two ranges to determine which is the lesser of the two
Mutating Algorithms
Algorithms that change the contents or order of the container are known as mutating algorithms.
Initialisation algorithms
fill()- Assigns a given value to every element in a given rangefill_n()- Assigns a given value to the firstnelements of a given rangegenerate()- Assigns the return value of a given function object to each element in a given rangegenerate_n()- Assigns the return value of a given function object to the firstnvalues in a given range
Modifying algorithms
for_each()- Performs an operation on each element for a given range, optionally mutating each elementtransform()- Apply a given unary function on every element in the range, stores the results in a destination range
Copy algorithms
copy()- Copies the contents of one range into another destination rangecopy_backward()- Copies the contents of one range into another, reversing the elements in the destination range
Removal algorithms
remove()- Removes all element of a given value from the given rangeremove_if()- Removes all elements matching a given unary predicate from a given rangeremove_copy()- Copies all elements from a given range to a destination range, except those matching a given valueremove_copy_if()- Copies all elements from a given range to a destination range, except those matching a given unary predicateunique()- Compares adjacent elements in a range, and removes subsequent duplicates; comparison can be done with an optionally provided binary predicate.unique_copy()- Copies all elements from a given range to a destination range, except adjacently duplicated elements
Replacement algorithms
replace()- Replaces every element in a given range matching a given value with a given replacement valuereplace_if()- Replaces every element in a given range matching a given unary predicate with a given replacement value
Sort algorithms
sort()- Sorts the elements in a range using a specified binary sort predicate; this may change the relative positions of elements that are equal.stable_sort()- Stable sort is similar to sort, but preserves the order of elements that are equalpartial_sort()- Sorts a specified number of elements in a rangepartial_sort_copy()- Copies a number of elements from a specified source range to a destination range, with the destination range in a sorted order
Partitioning Algorithms
partition()- Given a specified range, split the elements into two sets within it: those that satisfy the given unary predicate, and those that don't. This might not maintain the relative order of elements.stable_partition()- Partitions an input range into two sets just likepartition, but maintains the relative ordering of elements
Algorithms for sorted containers
binary_search()- Used to determine whether an element exists in a sorted collectionlower_bound()- Returns an iterator pointing to the first element in the range that is not less than a given valueupper_bound()- Returns an iterator pointing to the first element in the range that is greater than a given value
Finding Elements
The find() and find_if() algorithms help you find an element matching a particular value or condition.
Both functions return an iterator, which you need to compare against .end() or .cend() to verify the success of the find operation. Only if successful can you continue to use the iterator returned.
Counting Elements
The count() and count_if() algorithms help you count for elements matching a particular value or condition.
Searching
Finding is to look for one specific element matching a single value or condition. Searching is to look for a subsequence of values, or a pattern.
search() can be used to check the presence of one range within another range.
search_n() can be used to check if n instances of a particular value can be found consequently found in a container.
Both functions return an iterator to the first instance of the pattern found, which needs to be checked against .end() or .cend() to verify the success of the search operation.
Initialising Elements
fill() and fill_n() are algorithms that can set the contents of a given range to a particular value.
fill() is used to overwrite all elements in a range with a given value, whereas fill_n() overwrites the first n elements of a given range.
Initialising Elements at Runtime
Similar to the above, the generate() and generate_n() algorithms can set the contents of a given range using the values returned by a unary function object.
The main benefit in doing so is that the function object can contain state, producing a different value each time, and can also depend on runtime conditions, for example input by the user.
Processing Elements
The for_each() algorithm applies a given unary function object to each element in a given range.
The algorithm returns the function object that was used to process every element in the supplied range, which can be useful to retrieve state information after the invocation to for_each() is done.
Performing Transformations
The for_each() and transform() algorithms are similar in that they both invoke a function object for each element in a given range.
Though the transform() algorithm has two versions:
The first accepts a range, and a unary function, and can store the results of applying the unary function for each element into a destination range
The second accepts two ranges, and a binary function, and can store the results of applying the binary function for each pairwise element of the two ranges into a destination range
The first is commonly referred to as mapping (not to be confused with std::map), while the latter is commonly referred to as zipping.
Copying Elements
The three main copy functions are:
copy(), which copies the contents of one range into another, in the same order in the original rangecopy_if(), which copies elements from the original range that match a particular predicate into a destination rangecopy_backward(), which copies the contents of one range into another, in the reverse order of the original range
Removing Elements
The remove() and remove_if() functions removes all elements in a container matching a given value or predicate.
The functions return an iterator to the "new end" of the container, which we must use with the .erase member function of the container to resize the container accordingly.
The reason this is not automatically done for us is that the algorithms operate simply on a range of elements specified by two iterators, meaning that they have no knowledge of the underlying container or collection.
As a result, these functions do not actually "remove" the elements from the range - but rather they "move" all elements that are not subject to removal to the front of the range, keeping the relative order of elements.
This action of calling remove() then .erase() immediately after is known as the erase-remove idiom.
Replacing Elements
The replace() and replace_if() are functions that can replace elements in a collection matching a given value or predicate.
replace_if() expects a unary predicate that returns true for every element that needs to be replaced.
Algorithms for Sorted Collections
Sorting
The sort() algorithm can be used to sort a container.
By default sort() uses std::less<> as a binary predicate, which uses operator< to compare between two subsequent elements. You can also supply your own predicate to control the sort order.
Removing Duplicates
Subsequent duplicates can be removed from a sorted array using the unique() algorithm.
When this is invoked on a sorted array, this guarantees that the remaining elements are strictly unique since all duplicate elements would be neighbouring elements.
Similar to the remove() and remove_if() functions - you will need to resize the array with the .erase() member function after calling unique(). Think of the unique() algorithm as a fancy implementation of remove_if().
Searching
To search within a sorted array very quickly, you can use the binary_search() algorithm. This algorithm should only be called for containers already sorted.
This performs in logarithmic time, as opposed to linear time for a linear search.
Partitioning Elements
The partition() algorithm helps partition elements by rearranging them into two subranges: one that satisfies the given unary predicate, and another that does not.
The relative order of elements in each partition may not be preserved with partition(), for that behaviour you should use stable_partition() which does preserve the relative order of elements at a the price of performance (albeit small in most cases).
The function returns an iterator to the first element in the second group.
Inserting Elements in a Sorted Collection
Given an already-sorted collection, and an value that you wish to insert into the collection whilst maintaining the sorted order of the collection, you can use the lower_bound() and upper_bound() functions to help you determine the correct position to insert the new element.
The functions return iterators pointing to the minimal and maximal positions in a sorted range where an element can be inserted:
lower_bound()- Returns an iterator pointing to the first element in the range that is not less than a given valueupper_bound()- Returns an iterator pointing to the first element in the range that is greater than a given value
Last updated
Was this helpful?