STL: Algorithms - Kent State University

advertisement
STL Algorithms
algorithms independent of containers
STL Algorithms Description
•
•
•
•
independent of container types: operate on iterators
– operate on half-open range of elements of a container specified by
iterators
often behavior can be modified through callbacks – references to code
callbacks
– function pointers (C-style)
– function objects (functors)
– lambda expressions (C++11)
most algorithms are declared in <algorithm>, some are in
<numeric>
2
Algorithm Example: find
• looks for specific element in range
• needs <algorithm>
• find(beginRange, endRange, toFind)
•
•
•
returns iterator to first matching element in range of the container
– if associative – not necessarily first, use lower_bound
if not found – returns endRange (past last element)
linear complexity
find() method in map and set is faster (logarithmic), use it instead
find() method in list should be used instead
3
find_if with Function Pointer Callback
• find_if(beginRange, endRange, condition)
•
•
•
•
returns iterator to first element in range satisfying condition
third parameter is a callback
may be the name of a function (function pointer)
– need to accept element type
– need to be a predicate (return boolean)
example:
vector<int> vect;
…
auto it=find_if(vect.begin(), vect.end(), moreThan5);
…
bool moreThan5(int elem){
return elem>5;
}
4
Lambda Expressions
•
•
•
anonymous function
defined in C++11
syntax: [capture] -> returnType (parameters){body}
•
capture – passing discipline and (optionally) name of variables taken from
outside of scope of the lambda expressions
– [] no variables defined. Attempting to use any external variables in the
lambda is an error
– [x, &y] x is captured by value, y is captured by reference
– [&] any external variable is implicitly captured by reference
– [=] any external variable is implicitly captured by value
•
compiler may be able to deduce return type from return statement:
returnType is optional
•
•
if no parameters, parentheses are optional
example: []{cout << ”Hello, World!” << endl;}
•
can be assigned to function pointer variables
– watch out for implicit captures
can be used as parameters for other functions, have to conform to signature
•
5
count_if, generate, for_each
• count_if – counts number of elements that satisfy callback condition
int num=55;
int cnt = count_if(vect.begin(), vect.end(),
[num](int i){return i==num;});
• generate – fills elements with value returned by callback
generate(vect.begin(), vect.end(),
[]{return rand()%10;});
• for_each – executes callback for each element
for_each(vect.begin(), vect.end(),
[](int i){cout << i << " ";});
6
accumulate with various callbacks
•
•
accumulates data about container
two forms
accumulate(beginRange, endRange, initialValue) – sums elements,
sum initialized to initialValue, returns accumulated value
accumulate(beginRange, endRange, initialValue, callback)
invokes callback with two arguments, first is accumulator
•
callback can be function or lambda
int product(int num1, int num2){
return num1 * num2;
}
double mult = accumulate(vect.begin(), vect.end(), 1,
product);
or
double multLambda = accumulate(vect.begin(), vect.end(), 1,
[](int num1, int num2){return num1 * num2;});
7
Function Objects (Functors)
•
•
functor – object that may be invoked as a standalone function
done by overloading operator() may have any number of arguments
and return any value
class MyFunctor{
public:
MyFunctor(int x) : x_(x) {}
int operator() (int y) {return x_+y;}
private:
int x_;
};
…
•
then invoke like a standalone function
MyFunctor addOne(1); // creating a functor object
cout << addOne(2) << endl; // call it like a regular function
•
may keep state between calls.
– use this with caution for algorithms as implementations are free to
copy/invoke out of order/invoke concurrently
lambdas provide a convenient alternative
•
8
Predefined Functors, Arithmetic
•
•
•
•
STL provides a number of predefined functors
defined in <functional>
in std namespace (need to be imported or scope resolved)
arithmetic: plus, minus, multiplies, divides, modulus
•
have to be instantiated with type
plus<int> myPlus;
int result = myPlus(3,4);
cut << result << endl;
•
may be used in algorithms as callbacks
int sum = accumulate(vect.begin(), vect.end(), 0, plus<int>());
•
regular operators cannot be used as callbacks, functors are adapters that wrap regular
arithmetic operators
9
Comparison and Logical Functors
•
comparison functors: equal_to not_equal_to less greater less_equal
greater_equal
– less is used as default comparison in priority_queue container adapter
– may be changed, have to specify container, usually vector
– example: reversing sorting order in priority_queue
priority_queue<string, std::vector<string>,
std::greater<string>> workWeekR;
•
logical functors: logical_and logical_or logical_not
– example: logical_and in accumulate to determine if all boolean elements are true
vector<bool> flags;
…
bool allTrue=accumulate(flags.begin(), flags.end(), true,
std::logical_and<bool>());
10
Function Adapters (Binders)
•
•
binder (function adapter) – a specialized function that creates a function by assigning
(binding) a value of parameter of another function
bind() a C++11 feature – most flexible binder
newFunction bind(oldFunction, arguments)
where
– newFuncton – pointer to new function with bound parameters
– oldFunction – old function
– arguments – arguments to old function, in old-function parameter order
• free specified as _1 _2, etc defined in std::placeholders namespace
•
•
• bound
auto is useful as return type or it gets complicated
examples
auto f1 = bind(myFunc, _1, str); // binds second parameter to string str
auto f2 = bind(myFunc, _2, _1); // swaps parameters
11
Using Binders to Form Callbacks
•
binders useful in forming callbacks for algorithims inline
using namespace std::placeholders;
bool passingScore(int s, int threshold){
return s>=threshold;
}
...
// biding second argument of function passingScore to 70
auto it=find_if(vect.begin(), vect.end(),
bind(passingScore, _1, 70));
// binding second argument of standard functor greater_equal
auto it = find_if(vect.begin(), vect.end(),
bind(std::greater_equal<int>(), _1, 70));
•
last example is probably easier to read with lambda, how would you implement it?
12
Containers of Objects
•
algorithms perform on non-basic types correctly provided that proper operators are
defined
– e.g. operator< for sorting, operator== for searching
•
common task: invoke a method on each object
– suppose myclass declares myfunc() method and container cont holds
elements of myclass
may be accomplished as follows
for_each(cont.begin(), cont.end(), &myclass::myfunc);
– if need to pass parameters, use bind()
for_each(cont.begin, cont.end(), bind(&myclass::myfunc,
_1, value));
13
Algorithm Categories
•
•
utility – not operating on containers but useful
non-modifying – not updating the container
– search: min_element, max_element, find_first_of,
search, search_n
– comparison: equal, mismatch, lexicographical_compare
– operational: for_each
– numerical processing: count, count_if, accumulate
•
•
•
modifying – updating the container
sorting – sorting or (dis)ordering container
set – set functions
14
Utility Algorithms
•
min, max, minmax, swap
•
•
operate on a couple of elements
use operator<
•
•
use function templates
examples
int x=1,y=2;
cout << min(x, y); // prints1
cout << max(x, y); // prints 2
swap(x, y); cout<< x << y; // prints 21
auto pair = minmax(x,y);
cout << pair.first << pair.second; // prints 12
•
In C++11, utility algorithms operate on initializer lists: max({1,2,3,4,5});
15
Non-Modifying
Search Algorithms
•
•
•
•
•
•
•
•
•
•
•
return iterator to first element found
accept range
by default use opeator== or operator<
find, find_if, find_if_not – already covered
min_element, max_elment – locate element
auto it=min_element(vect.begin(), vect.end());
adjacent_find – finds the first pair of matching consecutive elements
find_first_of – finds first occurrence of elements in target range
search – finds target subsequence
search_n – finds consecutive elements
searches that work on ordered sequences (sorted vector, map, multimap,
set, multiset): binary_search, lower_bound, upper_bound,
equal_range
C++11 functions: find_if_not, minmax_element, all_of, any_of,
none_of
16
Non-Modifying
Comparison and Operational
•
•
comparison – compare entire ranges of elements
equal() – returns true if elements in both ranges are equal
mismatch() returns iterator to the first mismatched element
lexicographical_compare() – dictionary order comparison of
elements
operational
for_each() – executes callback on each element of the range: may print
a copy of every element, accumulate info about all elements, etc.
17
Modifying Algorithms
•
•
•
•
•
•
•
•
•
usually operate on two ranges: source range and destination (target) range,
ranges may be independent, overlapping or the same (in place operation)
transform() – similar to for_each() expects callback to return a value
to be stored in the target range
– variant: has two source ranges, callback accepts two parameters – one
for each source range and stores value for the target range. Can be
used to process two containers
– the target may be one of the source rages
copy() – copies source to target range
copy_if() – copies if callback returns true C++11
– returns iterator past the last element copied – can be used to trim
unused after copy elements
replace() – replaces elements with particular value with a different one
replace_if() – replaces by new value if callback returns true
reverse() – reverses elements in container
move() – moving elements with C++11 move semantics, leaves source
elements in unspecified but valid state
unique() – eliminates consequent duplicates – useful with sorted
containers
18
Modifying: Remove (and Erase)
•
•
remove() – removes elements with specific value
remove_if() – removes if callback returns true
•
•
both modifying algorithms
do not erase elements from containers (do not know if whole or full range)
– instead move remaining elements forward
– return iterator past last remaining elements
remove-erase-idiom – get the returned iterator and then use the container’s
erase() function to eliminate removed elements
•
•
– can be done in single line
removes are linear
– preferred to iterative erase() invocation – for random access
containers memory reorganization to keep continuous, results in
quadratic complexity
19
Sorting
•
•
•
•
•
sort() – n log(n) sort of the range
merge() – linear merge of sorted source ranges
– target range has to be large enough
– does not return iterator; no elements are removed – number of elements
in target container is sum of source sizes: use resize() or erase()
to trim target
unique() – eliminates duplicates, returns iterator past the last element
binary_search() – log(n) search in sorted container for a value, returns
true if found
– lower_bound() is same complexity but more useful
random_shuffle() – reshuffles range in linear time, internally uses rand()
20
Set
operate on sorted containers with unique elements, not necessarily sets; in fact,
sequential containers are recommended
• includes() – returns true if first range includes second
• set_union() – computes union (duplicates eliminated) from two source
ranges, puts it in destination range, returns pointer past last element
• set_intersection() – computes intersection of two source ranges
• set_difference() – difference (complement) of first range with second –
elements of first range that are not present in the second
• set_symmetric_difference() – elements of first range that are not
present in second and v.v.
21
Enhanced Iterator Functions
further enhance the power of algorithms
• iterator movement functions – makes iterator operate as
random access regardless of type
• reverse iterators – iterate in reverse direction
• inserters – target range does not have to match source range
22
Iterator Movement Functions
implemented as templates
• advance(iterator, position) – move iterator, position
elements, returns void, iterator needs to be at least input
– if iterator is input – moves copy of iterator by repeatedly calling
increment
– if iterator is random access – calls operator+(position)
• next(iterator, position) – returns iterator pointing position
elements forward, original iterator is not modified
• prev(iterator,position) - same as next in reverse direction
• distance(firstIterator, lastIterator) – returns the number
of elements between firstIterator and lastIterator. If iterators
are random access, uses subtract, otherwise repeatedly calls
increment++
23
Iterator Adapters
• declared in <iterator>
• reverse_iterator – iterates in reverse order (increment advances backward)
– rbegin() – returns reverse iterator starting at the last element of container
– rend() – returns iterator before the first element
– base() – returns underlying iterator plus one – useful to determine distance to
beginning
• insert iterators – special type of output iterators designed for algorithms (such as
copy) to insert rather than overwrite elements
– insert_iterator() – calls insert(position, element) on container
• is initialized with container, position
• inserter(container, position) returns insert_iterator on this
position
• useful for associative containers whose keys are usually not modifiable on
iteration
– back_insert_iterator() – calls push_back() on container
• back_inserter(container) returns back_insert_iterator for
this container
– front_insert_iterator() – calls push_front()
24
Download