2. C++ Avancé
2.8. Les Algorithmes de la STL
Les algorithmes de la STL sont des fonctions qui agissent sur les containers.
On distingue les algorithmes :
- mutables qui modifient le contenu du container : generate, reverse, transform
- des algorithmes non mutables qui ne modifient pas le contenu : count, count_if, find, ...
2.8.1. count, count_if
count permet de compter le nombre de valeurs égales à une constante,
count_if permet d'utiliser un prédicat (fonction) pour déterminer si chaque
valeur du container vérifie un critère donné.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <numeric>
using namespace std;
bool is_even(int x) {
return ((x % 2) == 0);
}
int main() {
vector<int> v { 1, 2, 3, 2, 5, 3, 7, 4, 9, 10 };
int how_many_2 = count(v.begin(), v.end(), 2);
cout << "the value 2 appears " << how_many_2 << " times" << endl;
int how_many_even = count_if(v.begin(), v.end(), is_even);
cout << "there are " << how_many_even << " even numbers" << endl;
return 0;
}
the value 2 appears 2 times
there are 4 even numbers
2.8.2. find
find permet de trouver la position (itérateur) d'une valeur constante,
find_if permet d'utiliser un prédicat (fonction) pour déterminer la position
de la valeur qui vérifie un critère donné.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <numeric>
using namespace std;
bool is_divisible_by_7(int x) {
return ((x % 7) == 0);
}
int main() {
vector<int> v { 1, 2, 3, 2, 5, 3, 14, 4, 9, 10 };
vector<int>::iterator position;
position = find(v.begin(), v.end(), 5);
if (position == v.end()) {
cout << "the value 5 was not found" << endl;
} else {
cout << "the value 5 was found at position " << position-v.begin() << endl;
}
position = find_if(v.begin(), v.end(), is_divisible_by_7);
if (position == v.end()) {
cout << "no value is divisible by 7" << endl;
} else {
cout << "the value " << *position << " at " << position-v.begin()
<< " is divisible by 7" << endl;
}
return 0;
}
the value 5 was found at position 4
the value 14 at 6 is divisible by 7
Note : certains containers (set, map) fournissent une methode find() qui est
plus efficace que l'algorithme générique find.
2.8.3. for_each
for_each applique une fonction à chaque élément du container. Attention
l'algorithme devient mutable si la fonction utilise une référence à la valeur &.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <numeric>
using namespace std;
void print_cube(int x) {
cout << (x*x*x) << " ";
}
void increase(int &n) {
n += 10;
}
int main() {
vector<int> v { 1, 2, 3, 4, 5 };
// print each element to the cube
for_each(v.begin(), v.end(), print_cube);
cout << endl;
// increase all elements by 10
// Note that increase uses a reference to n to allow the modification
for_each(v.begin(), v.end(), increase);
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
1 8 27 64 125
11 12 13 14 15
2.8.4. max_element, min_element, min_max_element (C++11)
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
// ----------------------------------------------
// function used to generate random numbers
// between 0 and 99
// ----------------------------------------------
int my_generator() {
return rand() % 100;
}
// ----------------------------------------------
// main function
// ----------------------------------------------
int main() {
srand(19702013);
// must define the size of the vector
vector<int> v(20);
// call user-defined function
generate(v.begin(), v.end(), my_generator);
// print vector contents
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
vector<int>::iterator it;
// find minimum element
it = min_element(v.begin(), v.end());
cout << "minimum = " << (*it) << endl;
// find maximum element
it = max_element(v.begin(), v.end());
cout << "maximum = " << (*it) << endl;
// C++11 minmax_element
pair<vector<int>::iterator, vector<int>::iterator> result;
result = minmax_element(v.begin(), v.end());
cout << "with minmax_elmeent C++11: " << endl;
cout << "minimum = " << *(result.first) << endl;
cout << "maximum = " << *(result.second) << endl;
return 0;
}
36 98 7 18 53 37 91 86 26 60 10 32 3 75 20 14 20 14 5 59
minimum = 3
maximum = 98
with minmax_elmeent C++11:
minimum = 3
maximum = 98
2.8.5. accumulate
L'algorithme accumulate réalise la somme des éléments du container.
On peut aussi l'utiliser avec une fonction à deux arguments pour réaliser un
produit.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <numeric>
using namespace std;
int product(int x, int y) {
return x * y;
}
int main() {
vector<int> v { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = accumulate(v.begin(), v.end(), 0);
cout << "sum = " << sum << endl;
int computed = v.size() * (v.size() + 1) / 2;
cout << "computed = " << computed << endl;
// factorial
int prod = accumulate(v.begin(), v.end(), 1, product);
cout << "product = " << prod << endl;
return 0;
}
sum = 55
computed = 55
product = 3628800
2.8.6. generate
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
// ----------------------------------------------
// function used to generate random numbers
// between 0 and 19
// ----------------------------------------------
int my_generator() {
return rand() % 20;
}
// ----------------------------------------------
// main function
// ----------------------------------------------
int main() {
srand(19702013);
// must define the size of the vector
vector<int> v(20);
// call existing function
generate(v.begin(), v.end(), ::rand);
// call user-defined function
generate(v.begin(), v.end(), my_generator);
// call lambda user-defined function
generate(v.begin(), v.end(), []() {
return rand() % 20;
});
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
2.8.7. reverse
Permet d'inverser le contenu du container :
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
int main() {
srand(19702013);
// must define the size of the vector
vector<int> v(20);
// call existing function
generate(v.begin(), v.end(), []() {
return ::rand() % 20;
});
// initial data
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// reverse data
reverse(v.begin(), v.end());
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
16 18 7 18 13 17 11 6 6 0 10 12 3 15 0 14 0 14 5 19
19 5 14 0 14 0 15 3 12 10 0 6 6 11 17 13 18 7 18 16
2.8.8. sort
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
int main() {
srand(19702013);
// must define the size of the vector
vector<int> v(20);
// call existing function
generate(v.begin(), v.end(), []() {
return ::rand() % 20;
});
// initial data
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// sort data
sort(v.begin(), v.end());
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
// sort in reverse order
sort(v.begin(), v.end(), std::greater<int>());
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
16 18 7 18 13 17 11 6 6 0 10 12 3 15 0 14 0 14 5 19
0 0 0 3 5 6 6 7 10 11 12 13 14 14 15 16 17 18 18 19
19 18 18 17 16 15 14 14 13 12 11 10 7 6 6 5 3 0 0 0
2.8.9. transform
16 18 7 18 13 17 11 6 6 0 10 12 3 15 0 14 0 14 5 19
average1 = 10.2
-16 -18 -7 -18 -13 -17 -11 -6 -6 0 -10 -12 -3 -15 0 -14 0 -14 -5 -19
average2 = -10.2