• Aucun résultat trouvé

Des algorithmes à gogo !

Dans le document La programmation en C++ moderne (Page 137-140)

Correction occurrence d’une valeur

II.10.1. Des algorithmes à gogo !

Maintenant, les itérateurs vont devenir vraiment intéressants et concrets, parce qu’ils sont pleinement employés parles algorithmesde la bibliothèque standard. Ces derniers, assez nom-breux, sont desfonctions déjà programmées et fortement optimisées pour manipuler des collections, permettant ainsi de les trier, de récupérer tous les éléments satisfaisant une certaine condition, etc. Nous n’en verrons que quelques-uns dans ce chapitre, mais une fois le principe compris, vous n’aurez aucune difficulté à utiliser les autres.

i

Fichier à inclure

La plupart des algorithmes se trouvent dans le fichier d’en-tête <algorithm>, pensez donc à l’inclure.

II.10.1.1.

std::count

 — Compter les occurrences d’une valeur

Commençons avec un algorithme simple, mais on ne peut plus utile: compter les occurrences d’une certaine valeur dans une collection. Cela se fait avec l’algorithme std::count. Celui-ci attend trois paramètres.

— Le premier est un itérateur pointant sur le début de la séquence.

— Le deuxième est un itérateur pointant sur la fin de la séquence.

— Le dernier est l’élément à compter.

La force de l’algorithme, c’est qu’il ne nous impose pas de chercher dans toute la collection. En effet, comme on manipule ici des itérateurs, rien ne nous empêche de compter les occurrences d’une valeur seulement entre le troisième et le septième élément de la collection, ou entre le cinquième et le dernier.

7 std::string const phrase {

"Exemple illustrant le tutoriel C++ de Zeste de Savoir." };

89 // Toute la collection.

10 auto const total_phrase { std::count(std::begin(phrase), std::end(phrase), 'e') };

11 std::cout << "Dans la phrase entière, il y a " << total_phrase

<< " 'e' minuscule." << std::endl;

1213 // Un sous-ensemble seulement de la collection.

14 auto const total_premier_mot { std::count(std::begin(phrase), std::begin(phrase) + 7, 'e') };

15 std::cout << "Dans le premier mot, il y a " <<

total_premier_mot << " 'e' minuscule." << std::endl;

1617 return 0;

18 }

Cet exemple utilise std::string, mais j’aurais tout aussi bien pu employer std::vector ou std::array. Par contre, std::list ne convient pas parce que … oui! j’ai fait std::be gin(phrase) + 7, ça suit dans le fond. Heureusement, une solution existe, que je vais vous montrer de suite.

II.10.1.2.

std::find

 — Trouver un certain élément

Vous remarquerez que le code précédent n’est pas de très bonne qualité, puisque j’ai écrit +7 directement, en dur. En plus du problème soulevé précédemment (ne pas pouvoir utiliser std::list), cela n’est pas très flexible: si le premier mot devient plus long ou plus court, je fausse les résultats. Alors qu’avec un itérateur qui pointerait sur le premier espace, on serait assuré d’avoir plus de souplesse. C’est justement ce que propose std::find, qui prend trois paramètres.

— Le premier est un itérateur pointant sur le début de la séquence.

— Le deuxième est un itérateur pointant sur la fin de la séquence.

— Le dernier est l’élément à rechercher.

Cette fonction retourne un itérateur sur le premier élément correspondant à la re-cherche, ou bien le deuxième argument si rien n’est trouvé.

1 #include <algorithm>

2 #include <iostream>

3 #include <string>

45 int main() 6 {

7 std::string const phrase {

"Exemple illustrant le tutoriel C++ de Zeste de Savoir." };

8

9 // On obtient un itérateur pointant sur le premier espace trouvé.

10 // Si l'on n'avait rien trouvé, on aurait obtenu std::end(phrase) comme valeur de retour.

11 auto const iterateur_premier_mot {

std::find(std::begin(phrase), std::end(phrase), ' ') };

1213 // On peut donc s'en servir ici. Même si l'on modifie la longueur du premier mot, on est assuré que cette solution marche.

14 auto const total_premier_mot { std::count(std::begin(phrase), iterateur_premier_mot, 'e') };

15 std::cout << "Dans le premier mot, il y a " <<

total_premier_mot << " 'e' minuscule." << std::endl;

16

17 return 0;

18 }

Je précise de nouveau pour être bien clair: std::find retourne un itérateur sur le premier élément trouvé, pas le deuxième ou le trousillième. Mais avec une simple boucle, rien ne nous empêche de récupérer la deuxième occurrence, ou la troisième.

Cela me donne d’ailleurs une excellente idée d’exercice. En utilisant les deux fonctions que nous venons de voir, nous allons faire un programme qui compte le nombre de 'e' dans chaque mot d’une phrase. Essayez de coder par vous-mêmes ce petit exercice. Une solution est proposée ci-dessous.

i

Un indice

Petite astuce avant de commencer: on peut initialiser une chaîne de caractères avec un itérateur de début et de fin, comme n’importe quel autre conteneur.

Contenu masqué n°25

II.10.1.3.

std::sort

 — Trier une collection

L’algorithme std::sort, fonctionnant, comme les autres, avec une paire d’itérateurs, permet de trier dans l’ordre croissant une collection d’éléments, que ce soit des nombres, des caractères, etc. Bien entendu, cet algorithme ne marchera que sur des conteneurs modifiables, c’est-à-dire non const. Voici un exemple tout simple qui ne devrait guère vous surprendre.

1 #include <algorithm>

2 #include <iostream>

3 #include <vector>

45 int main() 6 {

7 std::vector<double> constantes_mathematiques { 2.71828, 3.1415, 1.0836, 1.4142, 1.6180 };

8 std::sort(std::begin(constantes_mathematiques), std::end(constantes_mathematiques));

9

10 for (auto constante : constantes_mathematiques)

11 {

12 std::cout << constante << std::endl;

13 }

1415 return 0;

16 }

Si vous avez essayé de changer std::vector en std::list, vous vous êtes rendu compte que le code ne compile plus. En effet, std::sort attend en paramètre des itérateurs à accès direct, comme ceux destd::array,std::vector et std::string.

À l’opposé, std::list n’utilise que des itérateurs bidirectionnels. Il est donc impossible de trier une std::list en utilisant cet algorithme.

Dans le document La programmation en C++ moderne (Page 137-140)