Structures de données IFT-2000 Abder Alikacem Les listes ordonnées Programmation générique en...

Preview:

Citation preview

Structures de donnéesIFT-2000

Abder AlikacemAbder Alikacem

Les listes ordonnéesProgrammation générique

en C++

Semaine 3, suite et fin

Département d’informatique et de génie logiciel

Édition Septembre 2009

! +

Deuxième partie

Retour au type abstrait liste ordonnée, implantation par: des tableaux dynamiques (lab#3) des listes simplement chaînées des listes doublement chaînées des listes circulaires (anneaux)

Les listes ordonnées

Implantation dans une liste chaînée

// fichier Noeud.h// déclaration de la classe Noeud

#ifndef NOEUD_H#define NOEUD_H

class Noeud;typedef Noeud * elem;

template <typename T>class Noeud{ //Un noeud typique de la listepublic:

T el; //L'élément de base de la listeelem suivant; //Un pointeur vers le noeud suivantNoeud (const T& data_item, elem next_ptr = 0) :

el(data_item), suivant(next_ptr) {}~Nœud(){};

};#endif

elsuivant

Les listes ordonnées

Implantation dans une liste chaînée#ifndef LISTE_H#define LISTE_H#include "Noeud.h"#pragma warning( disable : 4290 )

template <typename T>class Liste {public:

Liste(){debut = 0;} // constructeur~Liste(); // destructeurListe(const Liste&) throw(bad_alloc); // constructeur de copievoid ajouter(T x, int pos) throw(range_error, bad_alloc);int taille() const;bool appartient(constT& x,) const;//Surcharge d'opérateursListe<T>& operator = (const Liste<T>&) throw (bad_alloc);friend ostream& operator << (ostream&, const Liste& );

private:elem debut; // Pointeur vers le dernier noeud de la liste

} ; #endif

Implantation dans une liste chaînée

Une meilleure version: utilisation d’une classe interne//…template <typename T>class Liste {public:

//ConstructeursListe(){debut = 0;} // constructeur Liste(const Liste&) throw(bad_alloc); // constructeur de copie~Liste(); // destructeur//Surcharge d'opérateursListe<T>& operator = (const Liste<T>&) throw (bad_alloc);

private:class Noeud{ //Un noeud typique de la listepublic: T el; //L'élément de base de la liste Noeud * suivant; //Un pointeur vers le noeud suivant Noeud (const T& data_item, Noeud * next_ptr = 0) :

el(data_item), suivant(next_ptr) {}};typedef Noeud * elem;elem debut; //Pointeur vers le premier noeud de la liste

} ;

Implantation dans une liste chaînée

template <typename T> Liste<T>:: ~Liste() { elem courant = debut; while(courant!=0) {

debut=debut->suivant; delete courant;courant=debut;

}}

~Liste() // destructeur

Destructeur

Implantation dans une liste chaînée

template <typename T>void Liste<T>:: ajouter(T x, int pos) throw(range_error, bad_alloc){

elem courant; //pointeur de service pour se promener dans la listeelem nouveau; //pour l'adresse de la nouvelle structure pour entreposer xint cpt=1; //compteur de boucle

//Vérification des hypothèses (préconditions)

//La positionif(pos<1 || pos > taille() +1) throw range_error( ..:Position d'ajout erronée");

//La mémoirenouveau = new Noeud(x); //on appelle le constructeur de la classe Noeud

//suite prochaine diapositive

ajouter() // l’ajout d’élément

Implantation dans une liste chaînée

//Cas où l'ajout se fait en première positionif(pos==1){

nouveau->suivant=debut;debut = nouveau;return ;

}//Ajout dans une autre quelconque positioncourant = debut; //on se positionne au début de la liste chaînéewhile (cpt< pos - 1){

courant=courant->suivant; //on passe à la structure suivante..cpt++; //...et on compte

}//A: courant pointe la structure d'avant le nouvel ajoutnouveau->suivant = courant->suivant; //on chaîne la nouvelle structure …courant->suivant = nouveau;//on chaîne la structure qui doit précéder …

}

ajouter() // l’ajout d’élément

Implantation dans une liste chaînée

template <typename T>void Liste<T>:: enleverEl(const T& x) throw(logic_error){ elem trouve = debut; elem pred;

//on prend pour acquis que l'opérateur != s'applique sur x, le mieux est … while (trouve != 0 && trouve->el != x ) {

pred = trouve; // pour marquer le noeud prédécesseur à celui qui contient xtrouve = trouve->suivant;

}

if (trouve== 0) throw logic_error("EnleverEl: x n'est pas dans la liste"); else { //suite prochaine diapositive

enleverEl() // enlever la première occurrence d’un élément

Implantation dans une liste chaînée

else {

if (debut == trouve){ / x est au début de la liste

debut = debut->suivant;}else{ // ..il est ailleur

pred->suivant = trouve->suivant;}

// on "coupe" la structure supprimée de la listetrouve->suivant = 0;//libération de la mémoire associée à la structure supprimée delete trouve;

}}

enleverEl() // enlever la première occurrence d’un élément

Implantation dans une liste chaînée

template <typename T>Liste<T>& Liste<T>::operator = (const Liste<T>& source)throw(bad_alloc){

//nettoyage ...if (debut!=0){ elem temp= debut;

while (debut !=0){

debut = temp->suivant;delete temp;temp = debut;

}}

//suite prochaine diapositive

Operator = () // surcharge de l’op. d’affectation

Implantation dans une liste chaînée

if (source.debut== 0)debut = 0; // la liste originale est vide

else { //la copie try{

//copie le permier noeud debut = new Noeud(source.debut->el); // copie le reste de la liste elem nouveau = debut; for(elem temp = source.debut->suivant; temp != 0;temp = temp->suivant) {

nouveau->suivant = new Noeud(temp->el);nouveau = nouveau->suivant;

}

}catch(exception&){ //suite dans la prochaine diapositive

Operator = () // surcharge de l’op. d’affectation

Implantation dans une liste chaînée

catch(exception&){ //Si on arrive ici c'est qu'il y a une erreur d'allocation //On doit donc libérer la mémoire déjà allouée elem temp= debut;

while (temp!=0){

debut = temp->suivant;delete temp;temp = debut;

} //On relance alors l'exception pour indiquer qu'une erreur est survenue throw; } }//else return (*this);}

Operator = () // surcharge de l’op. d’affectation

Implantation dans une liste chaînée

template <typename T>class Liste {public:

//..

friend ostream& operator << (ostream& f, const Liste& l){elem courant=l.debut; while(courant!=0){

f << courant->el << " "; courant=courant->suivant;

} return f;}

private://..

} ;

Operator << () // surcharge de l’op. <<

Les listes chaînées circulaires permettent de rendre l’écriture de certains algorithmes d’une manière plus efficace.

sommet

. . .

Implantation dans une liste circulaire (anneau)

Cependant, il est plus intéressant d’avoir un pointeur dernier au lieu d’un pointeur sommet

dernier

. . .

Listes circulaires (les anneaux)template <typename T>class Liste {public: //...

friend ostream& operator << (ostream& f, const Liste& l){if(l.dernier == 0) return f;elem courant = l.dernier->suivant; while(courant!=l.dernier){

f << courant->el << " "; courant=courant->suivant;

} f << l.dernier->el; return f;}

private:class Noeud{ public:

T el; Noeud * suivant;

Noeud (const T& data_item, Noeud * next_ptr = 0) : el(data_item), suivant(next_ptr) {}

};typedef Noeud * elem;elem dernier; /*Pointeur vers le dernier noeud de la liste*/

} ;

Dans les situations où il est souvent nécessaire d’atteindre des éléments d'une chaîne qui se trouvent quelques positions avant un élément donné, on peut alors adjoindre, à chaque élément, un pointeur supplémentaire vers son prédécesseur.

SommetG SommetD

Implantation dans une liste doublement chaînée

Nœud typique d’une liste chaînée :

Nœud typique d’une liste doublement chaînée :

Info Lien

PtrG Info PtrD

Implantation dans une liste doublement chaînée

template <typename T>class Liste {public:

//..

private: class Noeud{ //Un noeud typique de la liste public:

T el; //L'élément de base de la listeNoeud * suivant; //Un pointeur vers le noeud suivantNoeud * precedent; //Un pointeur vers le noeud précédent

Noeud (const T& data_item, Noeud * next_ptr = 0, Noeud * pred_ptr =0) : el(data_item), suivant(next_ptr), precedent(pred_ptr){}

}; typedef Noeud * elem; elem sommetG; //Pointeur vers le sommet à gauche elem sommetD; //...vers le sommet droit int cpt; //cardinalité de la liste} ;

Liste doublement chaînée

Ajouter un élément• Ajouter N avant P :

……

P

N

Ajouter un élément• Ajouter N avant P :

Pprecedentsuivant = NNprecedent = PprecedentNsuivant = PPprecedent = N

……

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N avant P :

PPprecedentprecedentsuivant = Nsuivant = NNprecedent = PprecedentNsuivant = PPprecedent = N

……

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N avant P :

Pprecedentsuivant = NNNprecedent = Pprecedent = PprecedentprecedentNsuivant = PPprecedent = N

……

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N avant P :

Pprecedentsuivant = NNprecedent = PprecedentNNsuivant = Psuivant = PPprecedent = N

……

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N avant P :

Pprecedentsuivant = NNprecedent = PprecedentNsuivant = PPPprecedent = Nprecedent = N

……

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N avant P :

Pprecedentsuivant = NNprecedent = PprecedentNsuivant = PPprecedent = N

……

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N après le sommet droit :

P

N

Liste doublement chaînée

template <typename T>class Liste {public:

//..

private: … elem sommetG; elem sommetD; int cpt;} ;

Ajouter un élément• Ajouter N après le sommet droit :

sommetDsommetDsuivant = Nsuivant = NNprecedent = sommetDsommetD = NNsuivant = 0

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N après le sommet droit :

sommetDsuivant = NNNprecedent = sommetDprecedent = sommetDsommetD = NNsuivant = 0

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N après le sommet droit :

sommetDsuivant = NNprecedent = sommetDsommetD = NsommetD = NNsuivant = 0

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N après le sommet droit :

sommetDsuivant = NNprecedent = sommetDsommetD = NNNsuivant = 0suivant = 0

P

N

Liste doublement chaînée

Ajouter un élément• Ajouter N après le sommet droit :

sommetDsuivant = NNprecedent = sommetDsommetD = NNsuivant = 0

P

N

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud avant P

……

P

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud avant P

N = PprecedentPprecedent = PprecedentprecedentPprecedentsuivant = PNsuivant = 0Nprecedent = 0delete NN = 0

……

P

N

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud avant P

N = PN = PprecedentprecedentPprecedent = PprecedentprecedentPprecedentsuivant = PNsuivant = 0Nprecedent = 0delete NN = 0

……

P

N

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud avant P

N = PprecedentPPprecedentprecedent = P = PprecedentprecedentprecedentprecedentPprecedentsuivant = PNsuivant = 0Nprecedent = 0delete NN = 0

……

P

N

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud avant P

N = PprecedentPprecedent = PprecedentprecedentPPprecedentprecedentsuivantsuivant = P = PNsuivant = 0Nprecedent = 0delete NN = 0

……

P

N

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud avant P

N = PprecedentPprecedent = PprecedentprecedentPprecedentsuivant = PNNsuivant = 0suivant = 0NNprecedent = 0precedent = 0delete NN = 0

……

P

N

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud avant P

N = PprecedentPprecedent = PprecedentprecedentPprecedentsuivant = PNsuivant = 0Nprecedent = 0delete delete NNN = 0N = 0

……

P

N

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud P

……

P

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud P

Pprecedentsuivant = PsuivantPsuivantprecedent = PprecedentPprecedent = 0Psuivant = 0delete P

……

P

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud P

PPprecedentprecedentsuivant = Psuivant = PsuivantsuivantPsuivantprecedent = PprecedentPprecedent = 0Psuivant = 0delete P

……

P

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud P

Pprecedentsuivant = PsuivantPPsuivantsuivantprecedent = Pprecedent = PprecedentprecedentPprecedent = 0Psuivant = 0delete P

……

P

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud P

Pprecedentsuivant = PsuivantPsuivantprecedent = PprecedentPPprecedent = 0precedent = 0PPsuivant = 0suivant = 0delete P

……

P

Liste doublement chaînée

Supprimer un élément• Supprimer le nœud P

Pprecedentsuivant = PsuivantPsuivantprecedent = PprecedentPprecedent = 0Psuivant = 0delete P

……

P

Liste doublement chaînée

Supprimer un élément• Supprimer le sommet gauche

N

Liste doublement chaînéetemplate <typename T>class Liste {public:

//..

private: … elem sommetG; elem sommetD; int cpt;

} ;

Supprimer un élément• Supprimer le sommet gauche

N = sommetGN = sommetGsommetG = sommetGsuivantsommetGprecedent = 0Nsuivant = 0delete NN = 0

N

Liste doublement chaînée

Supprimer un élément• Supprimer le sommet gauche

N = sommetGsommetG = sommetGsommetG = sommetGsuivantsuivantsommetGprecedent = 0Nsuivant = 0delete NN = 0

N

Liste doublement chaînée

Supprimer un élément• Supprimer le sommet gauche

N = sommetGsommetG = sommetGsuivantsommetGsommetGprecedent = 0precedent = 0Nsuivant = 0delete NN = 0

N

Liste doublement chaînée

Supprimer un élément• Supprimer le sommet gauche

N = sommetGsommetG = sommetGsuivantsommetGprecedent = 0NNsuivant = 0suivant = 0delete NN = 0

N

Liste doublement chaînée

Supprimer un élément• Supprimer le sommet gauche

N = sommetGsommetG = sommetGsuivantsommetGprecedent = 0Nsuivant = 0deletedelete N NN = 0N = 0

N

Liste doublement chaînée

Liste avec tableau:1. Insertion et suppression sont en O(n).2. Accès direct est en O(1).3. Tout l’espace est alloué à l’avance.4. Pas d’espace autre que les valeurs.

Liste dans une liste chaînée:1. Insertion et suppression sont en O(1).2. Accès direct est en O(n).3. L’espace augmente avec la liste.4. Chaque élément requiert de l’espace pour les pointeurs

Comparaison des implantations de la liste

Éléments du C++ à consulter

Semaine 1

Du C au C++Les entrées/sorties (important pour cette semaine) 

Semaine 2

Concepts orientés objet Classe et objetL'espace de nommageLes types vector et string 

Semaine 3

Programmation générique (template) La gestion des exceptions

Éléments du C++ à maîtriser

Les éléments syntaxiques nouveaux par rapport au langage Cdéclaration et initialisation de variablesle type bool, l’attribut constsurcharge de fonctions et arguments par défauttranstypage, espace de nommage et opérateur de résolution de portée

Notion de classe, constructeurs, destructeur

les attributs de masquage

Constructeur de copie et surcharge de l'op. = (minimum exigé dans une classe)

Les attributs et méthodes d'une classe: friend, static, const

La généricité (template)

Le point sur les normes de programmation

Normes de programmation:

• Commentaires d’interface• Commentaires d’implémentation• Découpage logique d’un programme• La gestion des exceptions• Style de programmation

Voir sur le site Web du cours, section Documentations/Normes de programmation:

•NormesProgrammation.pdf•Resume.h (à propos des commentaires Doxygen)

Nom de la classe Catégorie Descriptiondomain_error logique Lancée s'il se produit une erreur de domaine mathématique.invalid_argument logique Lancée si un des arguments d'une fonction est invalide.length_error logique Lancée si un objet aura une taille invalide. out_of_range logique Lancée si il y a une erreur avec un indice.

logic_error logique Lancée lors de n'importe quel autre problème de logique du programme.

Gestion des exceptions

#include <stdexcept>

Résumé des balises de Doxygen

L'interface...

/**

* \brief

*

* \pre

* \pre

*

* \post

* \post

*

* \exception

* \exception

*/

Implémentation

...

/**

* \fn

*

* \param[in]

* \param[out]

*

* \return

Section Documentations/Normes de programmation:

•Resume.h (à propos des commentaires Doxygen)

En-tête de fichiers

/**

* \file Liste.cpp

* \brief Le code des opérateurs de la liste.

* \author Abder

* \version 0.1

* \date septembre 2009

*

* Implémentation de la classe générique Liste.

*

*/

template <typename T> class Liste{

public://L'interface...

/**

* \brief Ajouter un nouvel élément dans la liste

*

* \pre il y a assez de mémoire pour ajouter l'élément x

* \pre la position d'ajout, pos, est comprise entre 1 et |L|+1

*

* \post la liste comprend un élément de plus

* \post la liste est inchangée sinon

*

* \exception range_error si la position est erronée

* \exception length_error si pas assez de mémoire

*/

void ajouter(T x, int pos) throw(range_error, length_error);

...

private:

...//Modèle d'implantation

};

Fichier Liste.h

Spécifications « C++ » (version Doxygen)

/**

* \fn void Liste<T>:: ajouter (T x, int pos)

*

* \param[in] x Élément à ajouter

* \param[in] pos Position où insérer l'élément

*

*/

template <typename T>

void Liste<T>::ajouter (T x, int pos) throw(out_of_range, length_error)

{

Commentaires d’implémentation (version Doxygen)

Structures de donnéesIFT-2000

Abder AlikacemAbder Alikacem

Les structures de piles et de files

Semaine 4

Département d’informatique et de génie logiciel

Édition Septembre 2009

! +

Première partie: les piles

• Introduction et exemples d’application• Description en terme de type abstrait• Implantation

Piles :

LIFO : last in, first outDAPS : dernier arrivé, premier sorti

in out

pile

Les primitives de manipulation ajouter un nouvel élément sur la pile (empiler, push) enlever un élément de la pile (dépiler, pop) regarder le premier élément de la pile (sommet, top) indiquer si la pile est vide regarder si un élément est sur la pile (examiner, peep) remplacer un élément sur la pile (changer, change)

pile

Piles

Préoccupation de la programmation par objet initialiser une pile (constructeurs); détruire une pile de ses éléments (destructeur); Constructeur de copie; Surcharge de l’opérateur =

La classe Piletemplate <typename T>class Pile{public:

// constructeurs et destructeursPile(); //constructeurPile(const Pile&) throw(bad_alloc); //constructeur copie~Pile(); //destructeur

// Modificateursvoid empiler(T) throw (bad_alloc);T depiler() throw(logic_error);

//Sélecteursbool estVide();int taille();T& sommet() throw (logic_error); // élément au sommet

//surcharge d'opérateursPile<T>& operator = (const Pile<T>&) throw

(bad_alloc);friend ostream& operator << (ostream& , const Pile& );

private: … //Modèle d’implantation};

Piles : implantation dans un tableau

template <typename T, int MAX = 100 >class Pile {public:

Pile(const int max = MAX) throw (bad_alloc);// constructeur... ~Pile (); // destructeur

private : T* tab; int sommet; int tailleMax;

};

Implantation dans un tableau dynamique

Piles : implantation dans un tableau

template <Typename T>Pile<T> :: Pile (int max) throw (bad_alloc){

tab = new T [max];sommet = -1;tailleMax =max;

}

template <class T>Pile<T> :: ~Pile (void) { if (tab!=0) delete [ ] tab;}

Constructeur

Destructeur

Piles : implantation dans un tableau

template <typename T>T Pile<T> :: depiler(void) throw (logic_error){

if (!estVide()) return tab[sommet--];else

throw logic_error("Depiler: la pile est vide!");}

template <typename T>bool Pile<T> :: estVide (void){

return (sommet == -1);}

dépiler

Sélecteur : vide

Piles : implantation dans un tableautemplate <typename T>void Pile<T> :: empiler(const T& e) throw (length_error){

if (sommet+1 < tailleMax) { sommet ++;

tab[sommet] = e; }else throw length_error("Empiler:la pile est

pleine\n");

}

empiler

Remarque : on suppose que l ’opérateur d ’affectation existe ou est surchargé dans la classe qui correspond au paramètre T.

=> intérêt de la surcharge des opérateurs

Piles : implantation dans un tableau

template <typename T>Pile<T>& Pile<T> :: operator = (const Pile<T>& p) {

if (tab!=0) delete [ ] tab; //on nettoie thistab=new T [p. tailleMax];

tailleMax =p.tailleMax;for (int i=0; i< tailleMax;i++)

tab[i]=p.tab[i];sommet=p.sommet;

return (*this);//retourner : une référence sur l ’objet courant}

Surcharge de l’op. =

Piles : implantation dans un tableau

template <typename T>Pile<T> :: Pile (const Pile<T>& p) {

tab=new X [p. tailleMax]; tailleMax =p. tailleMax;

for (int i=0; i< tailleMax;i+=1)tab[i]=p.tab[i];

sommet=p.sommet;}

Constructeur de copie

Piles : implantation dans une liste chaînée

template <typename T>class Noeud{public:

Noeud (const T& data_item, Noeud * next_ptr = 0) :el(data_item), suivant(next_ptr) {}//constructeur

~Noeud () {}; //destructeur qui ne fait rien

};

friend class Pile <T>;

private :T el;Noeud<T> * suivant;

Version 1Implantation dans une liste chaînée

Piles : implantation dans une liste chaînée

template <typename T>class Pile {public: Pile (); // Constructeur Pile (const pile<X>&) throw (bad_alloc); // Constructeur par

copie ~Pile (); // Destructeur

Pile<T>& operator=(const Pile<T>& P); // P1 = Pvoid empiler (const T& a) throw (bad_alloc); T depiler () throw (logic_error);

T& sommet (void) throw (logic_error); // sélecteur : valeur //placée au sommet

bool vide(); //sélecteur : est vide?

};

private :Noeud<T>* sommet; // pointeur sur le sommet de la pileint cpt; // Nombre d'élements de la pile void detruire (); //Méthode privée utile pour le destructeur

// et l’op. =

Version 1

Piles : implantation dans une liste chaînée

template <typename T>class Pile {public:

Pile (); Pile (const Pile<T>&) throw (bad_alloc); ~Pile (); Pile<T>& operator=(const Pile<T>& P); //..

private:class Noeud{public: T el;

Noeud * suivant;Noeud (const T& data_item, Noeud * next_ptr = 0) :el(data_item), suivant(next_ptr) {}

};

Noeud * sommet; //sommet de la pileint cpt; void detruire ();

};

Version 2Class Nœud interne

Piles : implantation dans une liste chaînée

template <typename T>Pile<T>::Pile (){ sommet =0; cpt = 0;}

template <class X>Pile<X>:: ~Pile(){ if (sommet != 0) detruire( );}

template <typename T>void Pile<T>::detruire () {

Noeud<T>* p;while (sommet != 0){

p=sommet->suivant;delete sommet;sommet=p;

}}

constructeur

destructeur

Les piles

Comparaison des 2 implantations Toutes les implantations des opérations d’une pile utilisant un tableau

ou une liste chaînée prennent un temps constant i.e. en O(1). Par conséquent, d’un point de vue d’efficacité, aucune des deux implantations n’est mieux que l’autre.

D’un point de vue de complexité spatiale, le tableau doit déclarer une taille fixe initialement. Une partie de cet espace est perdue quand la pile n’est pas bien remplie. La liste peut augmenter ou rapetisser au besoin mais demande un extra espace pour mémoriser les adresses des pointeurs.

Deuxième partie: les files

• Introduction et exemples d’application• Description en terme de type abstrait• Implantation

Files :

FIFO : first in, first outPAPS : premier arrivé, premier sorti

out in

file

Files

Primitives de manipulation:

ajouter un nouvel élément dans la file (enfiler); ôter l'élément le plus ancien de la file (défiler); indiquer si la file d'attente est vide; retourner le premier et dernier élément;

Préoccupation de la programmation par objet

initialiser une file (constructeurs); détruire une file de ses éléments (destructeur); Constructeur de copie; Surcharge de l’opérateur =

in

file

La classe Filetemplate<typename T>class File{public:

// constructeurs et destructeurs:File() throw(bad_alloc); //constructeurFile(const File &) throw(bad_alloc); //constructeur copie~File();// modificateursvoid enfiler(T) throw (length_error);T defiler() throw(logic_error);// sélecteurs

int taille() { return cpt;} bool estVide() { return cpt==0; } bool estPleine() { return cpt==TailleMax; }

T& premier() throw (logic_error); // élément en tête de la fileT& dernier() throw (logic_error); // élément en queue de la file// surcharges d'opérateursFile<T>& operator = (const File<T>&) throw (bad_alloc);friend ostream& operator << (ostream& f, const File& q);

private: // ...Modèle d'implantation};

T ê t e Q u e u e

Insérer 'Robert'

T Q

P a u l

R e n é

M a r c

P a u l

P a u l R e n é

R e n é M a r c

M a r c

M a r c

M a r c

M a r c

J e a n

J e a n

J e a n

A n n e

A n n e

T

T

T

T

T

T

T

Q

Q

Q

Q

Q

Q

QD ébordement

V ide

Insérer 'Paul'

Insérer 'Jean'

Insérer 'René'

Extraire 'Paul'

Extraire 'René'

Insérer 'A nne'

Insérer 'Marc'

Implantation par tableau circulaire

Implantation: liste circulaire

q = (q + 1) modulo MAXELT

Files: implantation dans un tableau

Implantation dans un tableau dynamique

template <typename T, int MAX = 100 >class File {public:

File(const int max = MAX) throw (bad_alloc);// constructeur ... ~File (); // destructeur

private : T* tab; int tete;int queue; int tailleMax;int cpt;

};

Tableau tab réservé dans le tas

Constructeur avec un paramètre : taille maximum

Files: implantation dans un tableau

template <Typename T>File<T> :: File (int max) throw (bad_alloc){

tab = new T [max];tete = 0;queue = 0;cpt = 0;tailleMax =max;

}

template <class X>File<X> :: ~File (void) { if (tab!=0) delete [ ] tab;}

Constructeur

Destructeur

Files: implantation dans un tableau

template <typename T>T File<T> :: defiler() throw (logic_error){

if (cpt!=0){

T elementaDefiler = tab[tete];tete = (tete+1)% tailleMax;cpt--; return elementaDefiler;

}else

throw logic_error("Defiler: la file est vide!");}

défiler

Files: implantation dans un tableau

template <typename T>T File<T> :: enfiler(const T& e) throw (length_error){

if(cpt<tailleMax){

tab[queue]= e;queue = (queue+1)%tailleMax;cpt++;

}else

throw length_error(« Enfiler: la file est pleine!");}

enfiler

Files: implantation par listes

Implantation dans une liste chaînéetemplate <typename T>class File {public:

File (); File (const File<T>&) throw (bad_alloc); ~File (); File<T>& operator=(const File<T>& P); //..

private:class Noeud{public: T el;

Noeud * suivant;Noeud (const T& data_item, Noeud * next_ptr = 0) :el(data_item), suivant(next_ptr) {}

};typedef Noeud * elem;elem tete; // pointeur sur la tête de la fileeleme queue; // Pointeur en queue de fileint cpt; // cardinalité de la file

};

Files: implantation par listes

template <typename T>Pile<T>::Pile (){ tete =0; queue = 0; cpt = 0;}

template <class X>File<X>:: ~File(){ if (tete != 0) {

Noeud<T>* p;while (tete != 0){

p=tete->suivant;delete tete;tete=p;

}}

constructeur

destructeur

Files prioritaires

Gestion d’une seule file• insertion se fait selon la priorité• éléments toujours triés selon leur priorité

in

file

41 84 1in

file

11 44 8

Laboratoire #4 (suite du lab#3)

Nous vous fournissons 3 packetages, un par projet/implantation que vous devez faire:

tableau dynamique (Lab#3)liste doublement chaînéeliste circulaire

Implantation d’une liste ordonnée

Dans chacun d'eux, vous devez compléter le fichier .inl étant donné le modèle d'implantation décrit dans la partie privée de la classe Liste. Bien entendu, les 3 implantations demandées doivent être génériques.  Ces 2 main() fournis sont pour tester les 3 packetages (séparément), un main() pour instancier une liste ordonnée d'entiers et un autre pour déclarer une liste d'objets définis dans la classe ClasseTests.h que nous vous fournissons également.

Recommended