Conteneurs STL

Transcription

Conteneurs STL
17/11/2010
Conteneurs STL
1
Bibliothèque de modèles standards (STL – Standard
Template Library)
STL est une bibliothèque de classes du type container (comme
par exemple des listes chaînées), d'algorithmes et d'outils
d'itération.




Un conteneur est une structure qui permet d'organiser un
ensemble d'objets du même type en séquence. Voici par
exemple différents types de conteneurs:
les listes (list),
les vecteurs (vector),
les ensembles (set),
les listes d'associations (map).
La notion de conteneur est importante. Il s'agit de structures
algorithmiques permettant d'organiser un ensemble de
données en séquence, puis de parcourir ces données.
2
1
17/11/2010
Namespaces :
La bibliothèque standard se trouve entièrement
dans le namespace std. Un namespace (espace de
nom ) est un moyen de lutter contre les conflits de
noms, par exemple le type list s'appelle en réalité
std::list.
Cependant pour ne pas alourdir les exemples de
code (et parce que en général, l'emploi de directives
using permet ce raccourci), nous omettrons le std::.
3
Certains noms sont assez communs et peuvent avoir été utilisés
par plusieurs librairies.
Les namespace sont une solution à ce problème. Le fichier suivant
namespace Lib
// ouverture du namespace
{
class Toto
{
// ...
};
};
// fermeture du namespace
définit le type Lib::Toto. Cependant quand aucune ambiguïté
n'existe, le programmeur peut utiliser le type Toto directement.
Pour utiliser le contenu du namespace Lib, il faut inclure
using namespace Lib;
4
2
17/11/2010
La notion d'itérateur :
L'itérateur est une généralisation des pointeurs. Il
permet de parcourir en séquence les éléments d'un
conteneur. Pour comprendre l'analogie, regardons
le code C++ classique suivant:
1 void fonction(char* t,const int& taille)
2{
3 for(int i=0;i<taille;i++)
4 {
5 t[i] = t[i]+2;
6 }
7}
5
Afin d'optimiser un tel parcours de tableau (pour
éviter à la ligne 5, de calculer deux fois un
déplacement de i par rapport à l'adresse de base de
t), on peut remplacer ce code par le code suivant:
void fonction(char* t,const int& taille)
{
for(char *p = t,*pstop = t+taille;p < pstop;p++)
{
*p = (*p)+2;
}
}
6
3
17/11/2010
vector<int>::iterator i;
Pour que cette itérateur pointe sur le premier
élément d'une liste donnée, on utilise la
méthode begin() de ce vecteur comme cidessous:
vector<int> v;
vector <int>::iterator i = v.begin();
7
Ainsi la traduction en STL de l'exemple précédent est:
void fonction(vector<char>& t)
{
for (vector<char>::iterator i = t.begin(),istop=t.end();
i != istop;++i)
{
*i = (*i)+2;
}
}
8
4
17/11/2010
Exemple :
// fichier vect.cpp (exemple des vecteurs : conteneur vector)
#include <iostream>
#include <vector>
using namespace std;
class Cercle {
private:
double rayon;
public:
Cercle(double rayon = 5.0) {
this->rayon = rayon;
}
double surface() {
return 3.14159* rayon*rayon;
}
void afficher(char * mess = "") {
cout << mess << "<rayon: " << rayon
<< ", surface: " << surface() << ">\n";
}
};
9
//afficher
void afficher(vector<Cercle> vect, char * message) {
if ( vect.size() == 0 )
cout << message << " est vide\n";
else {
int rang = 0;
cout << "Contenu de " << message << " de taille " <<
vect.size() << " :\n";
for ( vector<Cercle>::iterator iv = vect.begin(); iv !=
vect.end(); iv++)
{ cout << ++ rang << ")
";
iv -> afficher();
}
cout << endl;
}
}
10
5
17/11/2010
// deuxième manière pour afficher
void afficher(char * message, vector<Cercle> vect) {
if ( vect.size() == 0 )
cout << message << " est vide\n";
else {
int rang = 0;
cout << "(Acces via []) Contenu de " << message << " de taille " << vect.size() << " :\n";
for ( int i = 0 ; i < vect.size() ; i++)
{
cout << ++ rang << ")
";
vect[i].afficher();
}
cout << endl;
}}
// troisième manière pour afficher
void afficher(vector<Cercle> vect) {
if ( vect.size() == 0 )
cout << "Vecteur est vide\n";
else {
int rang = 0;
cout << "Vecteur de taille " << vect.size() << " :\n";
for(vector<Cercle>::reverse_iterator iv =vect.rbegin(); iv != vect.rend(); iv++)
{ cout << ++ rang << ")";
iv -> afficher();
}
cout << endl;
}}
11
int main(){
vector<Cercle> vect1;
afficher(vect1, "vect 1 au debut");
vect1.insert(vect1.begin(), Cercle(10.2));
vect1.insert(vect1.end(), Cercle(6.8));
vect1.insert(vect1.end(), Cercle(12.4));
vect1[0].afficher("premier cercle: ");
afficher(vect1, "vect 1 apres quelques ajouts");
afficher("vect 1 (par la deuxieme maniere)",vect1);
cout << "\n(par la troisieme maniere)Parcourir en sens inverse:\n";
afficher(vect1);
system("pause");
}
12
6
17/11/2010
13
Classe list :
La classe list est un conteneur ou chaque
élément de la liste a son propre segment de
mémoire et pointe son prédécesseur et son
successeur (liste doublement chainée).
Il faut inclure :
#include <list>
using namespace std ;
14
7
17/11/2010
Exemple :
// fichier list.cpp (exemple des listes : conteneur list)
#include <iostream>
#include <list>
using namespace std;
/* afficher le contenu d'une liste utilisant des itérateurs */
void afficher(list<int> liste, char * message) {
if ( liste.size() == 0 )
cout << message << " est vide\n";
else {
cout << "Contenu de " << message << ":\n";
for (list<int>::iterator il = liste.begin();
il != liste.end(); il++)
cout << *il << endl;
cout << endl;
// première et dernière valeur de la liste
cout << "Premier element : " << liste.front() << endl;
cout << "Dernier element : " << liste.back() << endl;
}
}
15
void demo1() {
list<int> liste1; // liste VIDE au début
cout << "\n\nDemo 1:\n\n";
afficher(liste1, "liste1 au debut");
// ajouter des multiples de 5 entre 1 et 50 au début de la liste
for (int k = 1 ; k <= 50 ; k++)
if (k % 5 == 0)
liste1.insert(liste1.end(), k);
afficher(liste1, "liste1 avec des multiples de 5 entre 1 et 50");
list<int>::iterator zz = liste1.end();
zz--;
cout << " ****************** " << * zz << " *********** \n";
// modifier la valeur du 1er élément
liste1.front() += 70;
// modifier la valeur du dernier élément
liste1.back() *= 2;
16
8
17/11/2010
// supprimer tous les 25 de la liste
liste1.remove(25);
afficher(liste1, "liste1 modifiee");
// trier (sort) la liste
liste1.sort();
afficher(liste1, "liste1 apres le tri");
// supprimer le début et la fin de la liste: liste1.pop_front();
liste1.pop_back();
afficher(liste1, "liste1 apres avoir retire le 1er et le dernier");
// ajouter au début et à la fin de la liste
liste1.push_front(30);
liste1.push_front(45);
liste1.push_back (15);
liste1.push_back (50);
liste1.push_back (30);
afficher(liste1, "liste1 apres avoir ajoute quelques val. au debut et a la fin");
liste1.sort();
afficher(liste1,"liste1 apres encore trie");
// enlever des valeurs répétées
liste1.unique();
afficher(liste1, "liste1 apres avoir enleve des val. doubles");
}
17
// une manière pour créer une liste à partir d'un tableau
void creer(list<int> & liste, int tableau[], int nbElem) {
for (int i = 0 ; i < nbElem; i++)
liste.insert(liste.end(), tableau[i]);
}
void demo2() {
cout << "\n\nDemo 2:\n\n";
int age1[] = { 23, 15, 20, 18, 22, 40, 18, 32 },
age2[] = { 15, 41, 22, 18, 26 };
list<int> liste1, liste2;
creer(liste1, age1, 8);
creer(liste2, age2, 5);
afficher(liste1, "liste 1 apres la creation");
afficher(liste2, "liste 2 apres la creation");
getchar();
liste1.sort();
liste2.sort();
// fusion de 2 listes
liste1.merge(liste2);
afficher(liste1, "liste 1 apres la fusion avec liste 2");
}
int main()
{
demo1();
demo2();
}
18
9
17/11/2010
19
20
10
17/11/2010
21
22
11
17/11/2010
23
24
12
17/11/2010
STL vector et list
Les tableaux (vector)
La classe vector est définie dans le fichier d'entête :
#include <vector>
Le tableau est le conteneur le plus pratique de la STL. Il encapsule
efficacement les tableaux dynamiques en gérant la réallocation et
les recopies.
Un tableau connait 2 valeurs:
sa taille: le nombre d'éléments qu'il contient,
sa capacité: le nombre d'éléments qu'il peut contenir.
Quand l'ajout d'un élément entraîne (taille>capacité) alors le tableau se réalloue en
doublant sa capacité (stratégie classique).
Pour déclarer un tableau contenant des int, on utilisera :
vector<int> v;
Le tableau a alors une taille nulle (on ne s'occupe pas de sa capacité).
Pour ajouter des éléments, on peut utiliser push_back,push_front.
25
Méthodes Description
begin() renvoie un itérateur sur le premier élément du vecteur.
end() renvoie un itérateur sur le dernier élément du vecteur.
assign() remplit le vecteur à la manière des constructeurs :
b.assign(a.begin(),a.end()) ;
ceci rempli le vecteur b avec le contenu du vecteur a.
Une autre utilisation de assign() :
b.assign(10,0) ;
rempli les dix premiers élément avec la valeur 0.
at() renvoie l’élément situé à la ième position :
a.at(10) ;
renvoie l’élément situé à la 11ième position (les vecteurs
commencent à l’indice 0)
26
13
17/11/2010
front() renvoie le premier élément du vecteur (ne renvoie pas un
itérateur).
back() renvoie le dernier élément du vecteur (ne renvoie pas un
itérateur).
capacity() renvoie le nombre de case mémoire disponible avant de
réallouer de la mémoire
clear() supprime tous les éléments du vecteur.
empty() renvoie un booléen indiquant si le vecteur est vide (true) ou
non (false)
erase() Supprime un élément ou une plage de valeur :
a.erase(10) ; //supprime le 11ème élément.
a.erase(a.begin(),a.end()) ; // equivalent à a.clear() ;
insert() insère un ou plusieurs éléments dans un vecteur.
a.insert(10,2) ; //insère la valeur 2 à la 11 ème place.
a.insert(10,2,3) ; //insère 2 fois la valeur 3 à partir de la 11ème
position.
pop_back() supprime et renvoie le dernier élement du
vecteur.
27
push_back() insère un élément à la fin du
vecteur.
reserve() ajoute n cases mémoires au vecteur.
resize() change la taille du vecteur.
size() renvoie le nombre d’élément du tableau
(attention différent de capacity() )
swap() échange deux éléments de deux
vecteurs.
28
14
17/11/2010
Pour accéder directement aux éléments d'un
tableau, en lecture ou en écriture, on utilise la
notation [] classique:
#include <vector>
#include <iostream>
using namespace std;
int main(){
vector<int> v;
v.push_back(3); // le tableau vaut [3] et est de taille 1
v.push_front(4); // le tableau vaut [4,3] et est de taille 2
cout<<v[0];
// renvoie 4
v[1] = 5;
cout<<v[1];
// renvoie 5
}
29
Attention, aucun contrôle de dépassement
d'indice n'est effectué (sinon la classe serait
trop lente et pas assez générique).
Si vous tentez d'accéder un élément au delà
de la taille du tableau, vous risquez le
plantage
30
15
17/11/2010
Les listes (list)
La classe list est définie dans le fichier d'entête
:
#include <list>
Pour déclarer une liste contenant des int, on
utilisera :
list<int> l;
31
Pour insérer ou retirer des éléments dans la
liste, on utilisera les commandes suivantes:
#include <list>
using namespace std;
void main(){
list<int> l;
l.push_front(3); // la liste vaut 3::[]
l.push_front(2); // la liste vaut 2::3::[]
l.push_back(4); // la liste vaut 2::3::4[]
l.pop_front(); // la liste vaut 3::4[]
l.pop_back(); // la liste vaut 3::[]}
32
16
17/11/2010
Les fonctions pop_back et pop_front ne retournent
pas de valeurs. Elles ne font que dépiler la valeur de
queue ou de tête.
Pour accéder à la valeur de queue ou de tête, sans
les dépiler, on utilisera:
l.front(); // Retourne la valeur en tête de liste
l.back(); // Retourne la valeur en queue de liste
Il est à noter que ces 2 fonctions retournent des
références, c'est à dire qu'on peut s'en servir pour
modifier le premier où le dernier élément d'une liste
comme dans l'exemple ci-dessous:
l.front() = 4;
33
Les méthodes:
size_t size() const;

Nombre d’élément.
void push_back(const T& x);

Ajoute l’élément x en fin de liste.
void pop_back();

Supprime le dernier élément de la liste.
iterator insert(iterator position, const T& x);

Insert l’élément x devant l’élément désigné par position.
iterator insert(iterator position);

Insert un élément construit par défaut devant l’élément désigné par position.
void insert(iterator position, const_iterator first, const_iterator last);

Insert une séquence d’élément désigné par first et last devant l’élément désigné par position.
iterator erase(iterator position);

Efface l’élément à la position donnée.
iterator erase(iterator first, iterator last);

Efface les éléments entre first et last exclus.
void clear();

Efface tous les éléments de la list.
34
17
17/11/2010
Les méthodes spécifique à la classe List:
void remove(T valeur)

Supprime tous les éléments égaux à valeur.
void sort()

Tri la liste dans l’ordre croissant.
void unique()

Elimine les éléments en double dans une liste triée.
void merge(const list<T>)

Fusionne la liste list avec la liste concernée. A la fin de
l’opération, list est vide.
35
18

Documents pareils