STL Algorithms in Action - Michael VanLoon - CppCon 2015
STL Algorithms in Action - Michael VanLoon - CppCon 2015
Michael VanLoon
CPPcon 2015
What are algorithms?
al·go·rithm
noun: algorithm; plural noun: algorithms
A procedure for solving a … problem (as of
finding the greatest common divisor) in a finite
number of steps that frequently involves
repetition of an operation; broadly: a step-by-
step procedure for solving a problem or
accomplishing some end especially by a
computer.
Merriam-Webster dictionary
vector<int> out;
bool found = false;
for (const auto& i: v) {
if (i >= 42) {
out.emplace_back(i);
++global_count;
if (i == 42) {
found = true;
}
}
}
• accumulate
• inner_product
• partial_sum
• adjacent_difference
• iota
• bsearch
• qsort
template<typename Cont>
uint32_t hash_all_strings(const Cont& v) {
auto hasher = for_each(v.begin(), v.end(), HashString());
return hasher.hash;
}
void test_for_each_hash() {
vector<string> v{ "one", "two", "three", "four", "five" };
uint32_t hash = hash_all_strings(v);
cout << "Hash: " << hash << dec << endl;
}
template<typename Cont>
uint32_t hash_all_strings(const Cont& v) {
auto hasher = for_each(v.begin(), v.end(), HashString());
return hasher.hash;
}
void test_for_each_hash() {
vector<string> v{ "one", "two", "three", "four", "five" };
uint32_t hash = hash_all_strings(v);
cout << "Hash: " << hash << dec << endl;
}
template<typename Cont>
uint32_t hash_all_strings(const Cont& v) {
const auto hasher = for_each(v.begin(), v.end(), HashString());
return hasher.hash;
}
void test_for_each_hash() {
vector<string> v{ "one", "two", "three", "four", "five" };
uint32_t hash = hash_all_strings(v);
cout << "Hash: " << hash << dec << endl;
}
template<typename Cont>
uint32_t hash_all_strings(const Cont& v) {
const auto hasher = for_each(v.begin(), v.end(), HashString());
return hasher.hash;
}
void test_for_each_hash() {
vector<string> v{ "one", "two", "three", "four", "five" };
uint32_t hash = hash_all_strings(v);
cout << "Hash: " << hash << dec << endl;
}
template<typename Cont>
vector<uint32_t> hash_each_string(const Cont& v) {
vector<uint32_t> res;
transform(v.begin(), v.end(), back_inserter(res), hash_string);
return res;
}
void test_transform_hash() {
vector<string> v{ "one", "two", "three", "four", "five" };
auto res = hash_each_string(v);
cout << "Hashes: ";
for_each(res.begin(), res.end(),
[](uint32_t rh){ cout << rh << " "; });
cout << endl;
}
template<typename Cont>
vector<uint32_t> hash_each_string(const Cont& v) {
vector<uint32_t> res;
transform(v.begin(), v.end(), back_inserter(res), hash_string);
return res;
}
void test_transform_hash() {
vector<string> v{ "one", "two", "three", "four", "five" };
auto res = hash_each_string(v);
cout << "Hashes: ";
for_each(res.begin(), res.end(),
[](uint32_t rh){ cout << rh << " "; });
cout << endl;
}
template<typename Cont>
vector<uint32_t> hash_each_string(const Cont& v) {
vector<uint32_t> res;
transform(v.begin(), v.end(), back_inserter(res), hash_string);
return res;
}
void test_transform_hash() {
vector<string> v{ "one", "two", "three", "four", "five" };
auto res = hash_each_string(v);
cout << "Hashes: ";
for_each(res.begin(), res.end(),
[](uint32_t rh){ cout << rh << " "; });
cout << endl;
}
inline bool
headers_valid(const vector<string>& headers) {
return all_of(headers.begin(), headers.end(),
[](const auto& header) -> bool {
smatch matches;
return regex_match(header, matches, reHeader);
}
);
}
output:
headers valid: true
headers valid: false
headers valid: false
headers valid: false
output:
headers valid: true
headers valid: false
headers valid: true
string find_header;
string find_value;
string find_header;
string find_value;
{
vector<string> h2 = { "Foo: bar", "Content-type: application/json", "X-SuperPower: supersmell", "Accept: text/ht
ml,text/json,application/json" };
const HeaderData& hd = header_parse(h2, "X-SuperPower", "toestrength");
cout << "headers parse: " << hd << ", good " << hd.good_headers << ", bad " << hd.bad_headers;
for_each(hd.found_headers.begin(), hd.found_headers.end(), [](const auto& val) {
cout << "\n\t'" << val.first << "', '" << val.second << "'";
});
cout << endl;
}
{
vector<string> h3 = { "Foo : bar", "Content-type: application/json", "X-Superpower: toestrength", "Accept: text/
html,text/json,application/json" };
const HeaderData& hd = header_parse(h3, "X-SuperPower", "toestrength");
cout << "headers parse: " << hd << ", good " << hd.good_headers << ", bad " << hd.bad_headers;
for_each(hd.found_headers.begin(), hd.found_headers.end(), [](const auto& val) {
cout << "\n\t'" << val.first << "', '" << val.second << "'";
});
cout << endl;
}
}
if (it == v.end())
cout << "Vector is sorted" << endl;
else
cout << "Vector not sorted, value " << *(it + 1)
<< ", at position " << it - v.begin() + 1 << endl;
output:
Vector is sorted
Vector not sorted, value 3, at position 9
v.push_back(2.0);
it = checkDeviation(v, 0.1);
if (it == v.end())
cout << "Vector is within deviation limits" << endl;
else
cout << "Vector outside deviation limits, values " << *it << " and ”
<< *(it + 1) << ", at position " << it - v.begin() + 1 << endl;
output:
Vector is within deviation limits
Vector outside deviation limits, values 1.2 and 2, at position 7
vector<Foo> v;
v.erase(
remove_if(v.begin(), v.end(),
[](const Foo& foo){ return foo.expired; }),
v.end());
Output:
before: [val: 1, expired: false] [val: 2, expired: true] [val: 3,
expired: false] [val: 4, expired: false] [val: 5, expired: true]
after: [val: 1, expired: false] [val: 3, expired: false] [val: 4,
expired: false]
• Sorting algorithms:
– sort1
– stable_sort1
– partial_sort, partial_sort_copy1
• Sorta-sorts:
– nth_element1
– partition, partition_copy2
– stable_partition2
1 Requires random access iterators
2 Requires bidirectional iterators
• sort • partial_sort
– Most general-purpose sort – Sort a subset of a sequence,
– Order of equivalent items drawing from a subset that is
implementation-defined equal to or larger than the sorted
– In some cases, may be more sequence
efficient than stable_sort – There is no stable version of
since equivalent items can be partial_sort
rearranged at sort’s discretion • partial_sort_copy
– Sorts in place
– Like partial_sort, but…
• stable_sort – Sorts specified subset of an
– Order of equivalent items input sequence, emitting to an
preserved output sequence
– Sorts in place
stable_sort(v.begin(), v.end(),
[](const Person& a, const Person& b){ return a.first < b.first; });
stable_sort(v.begin(), v.end(),
[](const Person& a, const Person& b){ return a.last < b.last; });
// Sort by most influential data last
stable_sort(v.begin(), v.end(),
[](const Person& a, const Person& b){ return a.first < b.first; });
stable_sort(v.begin(), v.end(),
[](const Person& a, const Person& b){ return a.last < b.last; });
// Sort by most influential data last
stable_sort(v.begin(), v.end(),
[](const Person& a, const Person& b){ return a.first < b.first; });
stable_sort(v.begin(), v.end(),
[](const Person& a, const Person& b){ return a.last < b.last; });
// Sort by most influential data last
partial_sort(v1.begin(),
v1.begin() + 5,
v1.begin() + 8,
greater<int>());
STL Algorithms in Action Michael VanLoon - http://codeache.net - CPPcon 2015 52
partial_sort example
vector<int> v1{ 42, 17, 89, 22,
34, 78, 63, 12,
57, 99 };
partial_sort(v1.begin(),
v1.begin() + 5,
v1.begin() + 8,
greater<int>());
STL Algorithms in Action Michael VanLoon - http://codeache.net - CPPcon 2015 53
partial_sort example
vector<int> v1{ 42, 17, 89, 22,
34, 78, 63, 12,
57, 99 };
partial_sort(v1.begin(),
v1.begin() + 5,
v1.begin() + 8,
greater<int>());
STL Algorithms in Action Michael VanLoon - http://codeache.net - CPPcon 2015 54
partial_sort example
visual
first first
42 89
17 78
89 63 sort output range
22 42
sort input range
34 34
middle
78 17
63 22
12 12
last
57 57
99 99
• nth_element
– Reorders sequence such that all items before “nth”
are less, and all items after “nth” are not less
– Order of items in lower and upper subsets is
implementation defined
– Order of equivalent items is implementation-
defined
– “nth” element is exactly the value that would exist
in a fully sorted sequence (but without fully sorting)
– Operates in place
partition nth_element
• partitions a sequence, based • partitions a sequence, based
on condition on position
• partition point is not • nth element is element that
guaranteed to be value that would exist in that position in
would be at that position in
fully sorted sequence
fully sorted sequence
• input: • input:
– sequence begin, end – sequence begin, end
– comparison function – iterator to “nth” position
• output: – optional comparison function
– reordered sequence • output:
– iterator to partition point – reordered sequence, partitioned
around nth element
vector<int>::iterator part_it =
partition(v.begin(),
v.end(),
[](const int i) {
return i < 50;
});
vector<int>::iterator part_it =
partition(v.begin(),
v.end(),
[](const int i) {
return i < 50;
});
partition_copy(v.begin(),
v.end(),
back_inserter(smaller),
back_inserter(larger),
[](const int i) {
return i < 50;
});
STL Algorithms in Action Michael VanLoon - http://codeache.net - CPPcon 2015 62
partition_copy example
visual: partition elements around 50
input sequence
12
12
31
89
18 output sequence
31 < 50
7 (condition true)
18
49
7
49
72
69
89
50
72
49 output sequence
69
50 not < 50
50 (condition false)
51
50
49
51
vector<Employee> v{
{ "Joe", "P", "Smith", Employee::EmployeeType::Manager },
{ "Jane", "Q", "Jones", Employee::EmployeeType::Junior },
{ "Frank", "P", "Johnson", Employee::EmployeeType::Architect },
{ "Sarah", "B", "Smith", Employee::EmployeeType::Executive },
{ "Joe", "X", "Jones", Employee::EmployeeType::Senior },
{ "Joe", "A", "Smith", Employee::EmployeeType::Junior },
{ "Chris", "M", "Williams", Employee::EmployeeType::Manager }
};
executives get the company jet; managers get the company car
vector<Employee>::iterator car_it =
partition(management.begin(), management.end(),
[](const Employee& e) {
return e.type == Employee::EmployeeType::Executive;
});
vector<Employee>::iterator jet_it = management.begin();
output:
49 2 12 49 18 7 50 >50< 51 78 72 69 81 89
output:
49 2 12 49 18 7 50 50 51 69 >72< 78 81 89
partial_sort(vec.begin(),
vec.begin() + 20,
vec.end(),
greater<int64_t>());
nth_element(vec.begin(),
vec.begin() + 20,
vec.end(),
greater<int64_t>());
sort(vec.begin(), vec.begin() + 20,
greater<int64_t>());
vector<int64_t> v1 = init_vec();
vector<int64_t> v2 = v1; // make a copy
cout << "sorted portions of vectors are equal: " << boolalpha
<< equal(v1.begin(), v1.begin() + 20, v2.begin()) << endl;
cout << "unsorted portions of vectors are equal: " << boolalpha
<< equal(v1.begin() + 20, v1.end(), v2.begin() + 20) << endl;
output:
sorted portions of vectors are equal: true
unsorted portions of vectors are equal: false
vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
vector<int>::iterator it = v.begin() + 2;
int i = *it;
v.erase(it);
Output:
before: 0 1 2 3 4 5 6 7 8 9
After: 0 1 3 4 5 2 6 7 8 9
vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
vector<int>::iterator it = v.begin() + 2;
int i = *it;
v.erase(it);
Output:
before: 0 1 2 3 4 5 6 7 8 9
After: 0 1 3 4 5 2 6 7 8 9
vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
vector<int>::iterator it = v.begin() + 2;
vector<int>::iterator it2 = v.begin() + 6;
rotate(it, it + 1, it2);
Output:
before: 0 1 2 3 4 5 6 7 8 9
After: 0 1 3 4 5 2 6 7 8 9
vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
vector<int>::iterator it = v.begin() + 2;
vector<int>::iterator it2 = v.begin() + 7;
rotate(it, it + 3, it2);
Output:
before: 0 1 2 3 4 5 6 7 8 9
after: 0 1 5 6 2 3 4 7 8 9
f p
l r
r f
p l
rf
rf
rl
rl
set_difference(current.begin(), current.end(),
update.begin(), update.end(),
back_inserter(removed_items));
remove_config(removed_items);
set_difference(update.begin(), update.end(),
current.begin(), current.end(),
back_inserter(new_items));
add_config(new_items);
set_difference(current.begin(), current.end(),
update.begin(), update.end(),
back_inserter(removed_items));
remove_config(removed_items);
set_difference(update.begin(), update.end(),
current.begin(), current.end(),
back_inserter(new_items));
add_config(new_items);
output:
Removed: five two
Added: seven six
• accumulate
• inner_product
• partial_sum
• adjacent_difference
• iota