Choisissez votre style : colorisé, impression

Série 26 :
Librairie standard

Buts

Cette série vous permettra de pratiquer les notions de containers et d'itérateur de la librairie standard.

Préliminaires :

Avant de commencer les exercices décrits dans cette série, créez le répertoire ~/Desktop/myfiles/Programmation/cpp/serie26 et travaillez dans ce répertoire pour les exercices ne faisant pas partie du projet. 
Si vous n'avez pas le temps de faire la partie "exercices" de la série, veillez au moins à en consulter le corrigé.


Cette série ne contient pas d'exercice de niveau 0.


Exercice 1 : Ensembles et itérateurs (niveau 1)

Exercice n°66 (pages 171 et 363) de l'ouvrage C++ par la pratique.

Le but est ici de vous faire pratiquer la notion d'itérateur.

Dans un fichier iterator.cc, définisez (en utilisant la librairie standard) un ensemble (set) de caractères contenant 3 éléments (par exemple 'a', 'b' et 'c')

Parcourez cet ensemble à l'aide d'un itérateur pour l'afficher élément par élément.

Définissez une chaîne de caractères (string) et utilisez ensuite l'algorithme de copy (et 2 itérateurs) pour copier le contenu de l'ensemble dans la string.
(Affichez la string pour vérifier).

Si vous voyez ce que je veux dire, terminer en affichant l'ensemble directement à l'écran en utilisant l'algorithme de copy et un ostream_iterator.


Exercice 2 : tris revisités (niveau 1)

Exercice n°67 (pages 172 et 365) de l'ouvrage C++ par la pratique.

Créez un tableau dynamique d'entiers ou de réels. Remplissez le avec des valeurs tirées au hasard.

Triez ce tableau en utilisant la librairie standard et affichez le résultat.


Exercice 3 : map, itérateurs (niveau 1 puis 2)

Un laboratoire de l'EPFL a écrit un programme pour simuler un système physique. Ce programme utilise un vecteur de données (des entiers) en entrée, et pour chacune de ces valeurs, simule l'évolution du système. Lorsque toutes les simulations ont été effectuées, il retourne un vecteur de résultats (sous forme de doubles). Les contenus des deux vecteurs sont donc liés et il est nécessaire de modifier ces contenus conjointement : si l'on supprime le k ieme élément du vecteur d'entrées, il faut aussi supprimer le k ieme élément du vecteur des résultats pour que les données soient cohérentes. Il serait donc plus naturel de regrouper ces deux vecteurs dans une table de definitions (template map, librairie standard), afin de manipuler leur contenu plus facilement, et d'éviter des erreurs lorsqu'une valeur est supprimée du vecteur d'entrée, mais pas du vecteur de résultats par exemple. On suppose que chaque entier du vecteurs d'entrée est unique. On vous demande d'écrire :
  1. une fonction remplit_map qui prend deux vecteurs en paramètre et retourne une map avec le contenu de ces vecteurs.
  2. une fonction afficher_map affichant le contenu de la map, par exemple sous la forme suivante :
    0  -> 0
    1  -> 3.1
    2  -> 6.2
    3  -> 9.3
    11 -> 10.5
    
             
    
  3. une fonction supprimer qui supprime de la map l'entrée correspondant à l'entier i
  4. (niveau 2) : une fonction supprimer_pair qui supprime de la map toute entrée correspondant à entier pair i
Vos parcours de structures de données (y-compris pour les vecteurs) se feront au moyen d'iterateurs.

Exercice 4 : chemin parcouru (niveau 3)

Pour vous faire estimer le chemin parcouru depuis le début de l'année, je vous propose de reprendre l'exercice 3 de la série 7.

Cet exercice est niveau 3 car je vais vous demander d'utiliser plusieurs des concepts des plus avancés que nous avons vu, combinés : POO, programmation générique, surcharge d'opérateurs et exceptions.

Vous pouvez cependant essayer de faire cet exercice à votre niveau (par exemple sans programmation générique ou sans surcharge) en en suivant l'esprit : comment feriez vous maintenant un programme de manipulation de matrice.

(niveau 3) Créez un modèle de classe Matrice prennant un type abstrait en argument, et héritant de tableau dynamique de tableau dynamique (2 fois) sur ce type.

Ajoutez à ce modèle de classe les constructeurs et destructeur qui vous parraissent nécéssaires.

Surchargez maintenant les opérateurs de multiplication (*, attention il est non commutatif pour les matrices ! ne vous trompez pas de sens), d'affichage (<<) et de lecture (>>) (ancien lire_matrice), de sorte que le main suivant :

double scalaire(double u[], double v[], int taille);
// ======================================================================
Matrice<double> saisie_matrice() {
  cout << "Saisie d'une matrice :" << endl;
  cout << "  Nombre de lignes :" << flush;
  unsigned int n;
  cin >> n;
  cout << "  Nombre de colonnes :" << flush;
  unsigned int m;
  cin >> m;
  Matrice<double> M(n,m);
  cin >> M;
                  
  return M;
}

// ======================================================================
int main()
{
  Matrice<double> M1(saisie_matrice());
  Matrice<double> M2(saisie_matrice());
  Matrice<double> M;
  try {
    M = M1 * M2;
  }
  catch (Matrice<double>::error e) {
  switch (e) {
     case Matrice<double>::WRONG_SIZES:
     cerr << "Multiplication de matrices impossible !" << endl;
     break;
  }
 }
 cout << "Résultat :" << M << endl;
 return 0;
}
puisse produire par exemple (inspiré de la série 3) :
Saisie d'une matrice :
Nombre de lignes : 2
Nombre de colonnes : 3
Entrez la matrice :
1 2
3 4
5 6
Saisie d'une matrice :
Nombre de lignes : 3
Nombre de colonnes : 4
Entrez la matrice :
1 2 3 4
5 6 7 8
9 0 1 2
Résultat :
38 14 20 26
83 38 53 68

Si vous êtes motivés, complétez la classe par des méthodes/opérateurs usuels : addition, soustraction, et si vous êtes vraiment très motivé (et fort en algèbre linéaire) (il est en train de devenir niveau 4 mon exercice !) par les méthodes determinant et inverse (lorsque cela à un sens), et l'opérateur division (multiplication à droite par l'inverse de l'opérande).


Projet : continuation

Cette semaine, vous devez commencer à coder la partie du projet décrite au point 2.5 de l'énoncé.