Listes, files et piles
Thèmes abordés
• Introduction à l’analyse de la complexité algorithmique
• TDA Liste
• TDA Liste
– Implémentation sous forme de tableau.
– Opérations élémentaires. Analyse de la complexité.
• TDA Liste chaînée
– Introduction aux structures de données récursives.
– Liste simplement chaînée, opérations et complexité.
– Liste doublement chaînée, opérations et complexité.
A t TDA
• Autres TDA – Files, piles
– Aperçu des arbres et des graphes.
• Quelques algorithmes de tri – Analyse de complexité
Introduction à la complexité algorithmique
Analyse des temps d’exécution des algorithmes
• Le temps d’exécution d’un algorithme dépend
De l’organisation de traitements dans l’algorithme figé – De l’organisation de traitements dans l’algorithme.
– Des données entrante dans l’algorithme.
– De la qualité du code généré par le compilateur.
– De la rapidité d’exécution du microprocesseur.
• Nécessité de pouvoir prédire le pire temps d’exécution
– Pour pouvoir garantir une réactivité acceptable des applications.
figé
figé figé variable
Analyse et programmation 2 - Listes, files et piles 2
Introduction à la complexité algorithmique
Analyse des temps d’exécution des algorithmes
• On considère un algorithme
Rece ant en entrée ne donnée dépendant d’ n facte r N – Recevant en entrée une donnée dépendant d’un facteur N
• Peut être une valeur utilisée pour un calcul : factorielle(N).
• Peut être la taille d’une donnée : tableau ou liste de taille N.
– Temps d’exécution de cet algorithme: donné par une fonction
• T(N)
• Complexité algorithmique
– On dit que l’algorithme est de complexité O(f(n)) s’il existe On dit que l algorithme est de complexité O(f(n)) s il existe
• Une fonction f(n)
• deux constantes c et n0
– telles que
• Pour tout n > n0, T(n) < c . f(n)
Analyse des temps d’exécution des programmes – exemples simples
int produit(int a, int b) {
return a * b;
}
O(1)
}
int factorielle(int n) {
int i, resultat;
resultat = 1;
for (i = 2; i <= n; i++)
resultat = produit(resultat, i);
return resultat;
}
O(n)
Analyse et programmation 2 - Listes, files et piles 4
double developpement_limite_exponentielle(doublex, int n) {
double resultat = 0.0;
int i;
for (i = 0; i <= n; i++)
resultat = resultat + pow(x, i) / factorielle(i);
return resultat;
}
O(n2)
TDA Liste
Introduction – Les applications
Liste de fichiers
Liste d’imprimantes
Liste de périphériques
Liste d’utilisateurs
TDA Liste
Introduction – Les applications
Liste de livres
Analyse et programmation 2 - Listes, files et piles 6
TDA Liste
Introduction – Les applications
• Ce support de cours
Liste de diapositi es – Liste de diapositives
• Chaque diapositive
– Liste de symboles – Liste d’animations
• Un polygone
– Liste de segments
• Une feuille de calcul
– Liste de cellules
• Un document de traitement de texte
– Liste de caractères
Définition
• Une liste est
Une collection d’éléments de même t pe – Une collection d’éléments de même type.
– Par opposition à un tableau, le nombre d’éléments est variable.
– Les éléments peuvent être
• Des données de type simple : int, double, …
• Des données composées : struct, tableau.
• Illustration
Analyse et programmation 2 - Listes, files et piles 8
Illustration
– Exemples du cours basés sur une liste de réels.
TDA Liste – représentation sous forme de tableau
Les opérations
• Initialiseurs
Initialiser la liste – Initialiser la liste.
• Sélecteurs
– Taille, Accès à un élément, Vide, Pleine.
• Modificateurs
– Ajouter en fin, Insérer, Supprimer, Vider.
• Itérateurs
– Accéder aux éléments en séquence.
TDA Liste - tableau
Représentation interne sous forme de tableau à taille fixe
• Principe
Utilisation d’ n tablea à taille fi e s rdimensionné – Utilisation d’un tableau à taille fixe, surdimensionné
– Mémorisation du nombre d’éléments effectif dans une variable.
• Déclaration du type de données
#define CAPACITE_LISTE_TABLEAU 100
typedef double ELEMENT;
Rappel – TDA :
Analyse et programmation 2 - Listes, files et piles 10
typedef struct {
int nombre_elements;
ELEMENT elements[CAPACITE_LISTE_TABLEAU];
} LISTE_TABLEAU;
Une application n’accède jamais directement aux champs !
TDA Liste – représentation sous forme de tableau
Les opérations
#define INDICE_INVALIDE -1
void liste_initialiser(LISTE_TABLEAU* liste);
int liste_nombre_elements(LISTE_TABLEAU* liste);
int liste_pleine(LISTE_TABLEAU* liste);
int liste_vide(LISTE_TABLEAU* liste);
ELEMENT liste_element(LISTE_TABLEAU* liste, int indice);
int liste_position_element(LISTE_TABLEAU* liste, ELEMENT e);
// Resultat : indice de l'élément, ou INDICE_INVALIDE en cas d'échec int liste_ajouter(LISTE_TABLEAU* liste, ELEMENT e);
int liste_inserer(LISTE_TABLEAU* liste, int indice, ELEMENT e);
int liste_supprimer(LISTE_TABLEAU* liste, int indice);
Initialisation
• But
Préparer la liste à rece oir des éléments – Préparer la liste à recevoir des éléments.
– Initialement, la liste sera donc vide.
• Implémentation
void liste_initialiser(LISTE_TABLEAU* liste) {
liste->nombre_elements = 0;
}
Analyse et programmation 2 - Listes, files et piles 12
• Complexité O(1)
TDA Liste - tableau
Accès au nombre d’éléments
int liste_nombre_elements(LISTE_TABLEAU* liste) {
return liste->nombre_elements;
}
int liste_pleine(LISTE_TABLEAU* liste) {
return liste_nombre_elements(liste) ==
CAPACITE_LISTE_TABLEAU;
} }
int liste_vide(LISTE_TABLEAU* liste) {
return liste_nombre_elements(liste) == 0;
}
Réutilisation d’une opération du TDA
TDA Liste - tableau
Accès à un élément par position
ELEMENT liste_element(LISTE_TABLEAU* liste, int indice) {
if (indice >= 0 && indice < liste->nombre_elements) return liste->elements[indice];
else {
printf("Erreur d'indice\n");
return 0;
}
} Contrôles de validité du TDA
Analyse et programmation 2 - Listes, files et piles 14
}
TDA Liste - tableau
Recherche de la position d’un élément
int liste_position_element(LISTE_TABLEAU* liste, ELEMENT e) {
int i int i;
int indice;
indice = INDICE_INVALIDE;
for (i = 0; i < liste->nombre_elements; i++) if (liste->elements[i] == e)
{
indice = i;
break;
} }
return indice;
}
Complexité ?
Ajout d’un élément à la fin
int liste_ajouter(LISTE_TABLEAU* liste, ELEMENT e) {
{
int indice;
if (!liste_pleine(liste)) {
indice = liste->nombre_elements;
liste->elements[indice] = e;
liste->nombre_elements++;
}
Contrôle de validité du TDA
Analyse et programmation 2 - Listes, files et piles 16
} else
indice = INDICE_INVALIDE;
return indice;
} Complexité ?
TDA Liste - tableau
Insertion d’un élément à une position donnée
0 1 2 3 4 5 6 7 8 9 10 11 12 13
2.0 1.5 7.3 8.1 4.5 6.3
liste_inserer(liste, 2, 9.9);
2.0 1.5 7.3 8.1 4.5 6.3
0 1 2 3 4 5 6 7 8 9 10 11 12 13
2.0 1.5 7.3 8.1 4.5 6.3
1
6.3
2
4.5
3
8.1
4
7.3
0 1 2 3 4 5 6 7 8 9 10 11 12 13
1èreétape
0 1 2 3 4 5 6 7 8 9 10 11 12 13
2.0 1.5 7.3 8.1 4.5 6.3 6.3 9.9 7.3 8.1 4.5
5 2èmeétape
TDA Liste - tableau
Insertion d’un élément à une position donnée
int liste_inserer(LISTE_TABLEAU* liste, int indice, ELEMENT e) {
int i;
int i;
int resultat;
if (!liste_pleine(liste))
if (indice >= 0 && indice <= liste->nombre_elements) {
for (i = liste->nombre_elements; i > indice; i--) liste->elements[i] = liste->elements[i - 1];
liste->nombre_elements++;
liste->elements[indice] = e;
Analyse et programmation 2 - Listes, files et piles 18
resultat = indice;
} else
resultat = INDICE_INVALIDE;
else
resultat = INDICE_INVALIDE;
return resultat;
}
Complexité ?
TDA Liste - tableau
Suppression d’un élément à une position donnée
0 1 2 3 4 5 6 7 8 9 10 11 12 13
2.0 1.5 9.9 7.3 8.1 4.5 6.3
liste_supprimer(liste, 1);
2.0 1.5 9.9 7.3 8.1 4.5 6.3
0 1 2 3 4 5 6 7 8 9 10 11 12 13
2.0 1.5 9.9 7.3 8.1 4.5 6.3
5
6.3
4
4.5
3
8.1
2
7.3
1 1èreétape
9.9
2èmeétape 0 1 2 3 4 5 6 7 8 9 10 11 12 13
2.0 9.9 7.3 8.1 4.5 6.3 6.3
Suppression d’un élément
int liste_supprimer(LISTE_TABLEAU* liste, int indice) {
int i int i;
int resultat;
if (indice >= 0 && indice < liste->nombre_elements) {
for (i = indice + 1; i < liste->nombre_elements; i++) liste->elements[i - 1] = liste->elements[i];
liste->nombre_elements--;
resultat = indice;
}
Analyse et programmation 2 - Listes, files et piles 20
} else
resultat = INDICE_INVALIDE;
return resultat;
}
Complexité ?
TDA Liste - tableau
Suppression de tous les éléments
0 1 2 3 4 5 6 7 8 9 10 11 12 13
2 0 1 5 9 9 7 3 8 1 4 5 6 3 2.0 1.5 9.9 7.3 8.1 4.5 6.3
0 1 2 3 4 5 6 7 8 9 10 11 12 13
void liste_vider(LISTE_TABLEAU* liste) {
liste->nombre_elements = 0;
}
TDA Liste - tableau
Parcours de la liste en avant / en arrière
• Le parcours est facile à implémenter et efficace.
• Exemple
• Exemple
void afficher_liste(LISTE_TABLEAU * liste) {
int i, nombre_elements;
nombre_elements = liste_nombre_elements(liste);
printf("{");
for (i = 0; i < nombre_elements; i++) {
if (i 0)
Analyse et programmation 2 - Listes, files et piles 22
if (i > 0)
printf(", ");
printf("%lg", liste_element(liste, i));
}
printf("}");
}
TDA Liste - tableau
Analyse
• Avantages
Accès rapide à to t élément – Accès rapide à tout élément.
– Simplicité.
• Inconvénients
– Opérations d’insertion et de suppression lentes :
• Recopie de nombreux éléments.
• Peu efficace pour des listes volumineuses.
– Besoin de sur-dimensionner les tableaux Besoin de sur dimensionner les tableaux
• Occupation mémoire pas optimisée.
– Aucune flexibilité sur le nombre maximum d’éléments
• Lorsque le maximum prévu est atteint, plus de possibilité d’ajouter ne serait ce qu’un seul élément.
Représentation interne sous forme de tableau dynamique
• Pour pallier aux inconvénients du tableau fixe
Possibilité d’allo er d namiq ement n tablea – Possibilité d’allouer dynamiquement un tableau.
– Réallocation pour suivre la croissance de la liste.
• Levée des problèmes
– De surconsommation de mémoire.
– De manque de flexibilité.
• Maintien des problèmes d’efficacité
é
Analyse et programmation 2 - Listes, files et piles 24
– Opérations d’insertion et de suppression.
TDA Liste - tableau
Mise en œuvre avec un tableau dynamique
• Déclaration de la structure de données
typedef struct typedef struct {
int capacite;
int nombre_elements;
ELEMENT * elements; // tableau alloué dynamiquement } LISTE_TABLEAU;
TDA Liste – tableau
Mise en œuvre avec un tableau dynamique• Fonction privée pour l’allocation de la mémoire
static int liste_etablir_capacite(LISTE_TABLEAU* liste, int capacite_desiree) {
const int PAS_INCREMENT_CAPACITE = 10;
int succes;
int capacite;
ELEMENT * nouveau_tableau;
capacite = (1 + (capacite_desiree - 1) / PAS_INCREMENT_CAPACITE) *PAS_INCREMENT_CAPACITE;
if (liste->capacite != capacite) {
if (liste->elements == NULL) {
liste->elements = (ELEMENT *)malloc(sizeof(ELEMENT) * capacite);
succes = liste->elements != NULL;
} else {
nouveau tableau = realloc(liste >elements sizeof(ELEMENT) * capacite);
Analyse et programmation 2 - Listes, files et piles 26
nouveau_tableau = realloc(liste->elements, sizeof(ELEMENT) * capacite);
succes = nouveau_tableau != NULL;
if(succes)
liste->elements = nouveau_tableau;
}
if (succes)
liste->capacite = capacite;
} else
succes = 1;
return succes;
}
TDA Liste - tableau
Mise en œuvre avec un tableau dynamique
• Initialisation
void liste initialiser(LISTE TABLEAU* liste) void liste_initialiser(LISTE_TABLEAU* liste) {
liste->nombre_elements = 0;
liste->capacite = 0;
liste->elements = NULL;
liste_etablir_capacite(liste, 0);
}
Mise en œuvre avec un tableau dynamique
• Ajout
int liste ajouter(LISTE TABLEAU* liste ELEMENT e) int liste_ajouter(LISTE_TABLEAU* liste, ELEMENT e) {
int indice;
if (liste_etablir_capacite(liste, liste->nombre_elements + 1)) {
indice = liste->nombre_elements;
liste->elements[indice] = e;
liste->nombre_elements++;
}
Analyse et programmation 2 - Listes, files et piles 28
} else
indice = INDICE_INVALIDE;
return indice;
}
TDA Liste - tableau
Conclusions
• L’utilisation d’un TDA pour une liste est judicieux
Le passage d’ ne liste à taille fi e ers ne liste à taille ariable – Le passage d’une liste à taille fixe vers une liste à taille variable se fait sans aucun changement de spécification sur les opérations du TDA.
– Il faudrait cependant ajouter une opération :
• liste_finaliser
• Pour libérer la mémoire allouée.
• Dans la pratique
– Les listes basées sur des tableaux à taille variables sont très largement utilisées : C++, Java, C#.
– En particulier pour mémoriser des variables de petite taille.
– Souvent le cas en programmation orientée objet
Analyse et programmation 2 - Listes, files et piles 30
Variantes des listes : les piles
Introduction
• Rappel du fonctionnement d’une pile
Opérations : empiler dépiler – Opérations : empiler, dépiler – Le dernier entré est le premier sorti
• Last In, First Out : LIFO
Applications pratiques
• Dans la pratique
– Logiciels de bureautique – Logiciels de bureautique
• La fonction « annuler »
• La première opération annulée est la dernière effectuée
– Navigateur Web
• Fonction « précédent »
• La première page ouverte est la dernière
Analyse et programmation 2 - Listes, files et piles 32
ouverte est la dernière lue.
• Utilisées pour de nombreux algorithmes
– Ex : parcours d’arborescence.
Variantes des listes : les piles
Les opérations
• Initialiseur M difi t
• Modificateurs
– Empiler (PUSH) : ajoute un élément sur la pile.
– Dépiler (POP) : enlève l’élément au sommet de la pile.
• Sélecteurs
– Est vide
– Nombre d’éléments.
é é
– Elément situé au sommet.
Variantes des listes : les piles
Implémentation basée sur la liste tableau
#ifndef __PILE_H_
#define __PILE_H_
#include "ListeTableauDynamique.h"
typedef struct {
LISTE_TABLEAU liste;
} PILE;
void pile_initialiser(PILE * p);
void pile empiler(PILE * p, ELEMENT e);
Analyse et programmation 2 - Listes, files et piles 34
o d p e_e p e ( p, e);
ELEMENT pile_depiler(PILE * p);
int pile_vide(PILE * p);
int pile_nombre_elements(PILE * p);
ELEMENT pile_sommet(PILE * p);
#endif
Variantes des listes : les piles
Implémentation basée sur la liste tableau
void pile_initialiser(PILE * p) {
liste initialiser(&p >liste) liste_initialiser(&p->liste);
}
int pile_vide(PILE * p) {
return pile_nombre_elements(p) == 0;
}
int pile_nombre_elements(PILE * p) {
{
return liste_nombre_elements(&p->liste);
}
void pile_empiler(PILE * p, ELEMENT e) {
liste_ajouter(&p->liste, e);
Implémentation basée sur la liste tableau
ELEMENT pile_sommet(PILE * p) {
int indice sommet int indice_sommet;
indice_sommet = liste_nombre_elements(&p->liste) - 1;
if (indice_sommet >= 0)
return liste_element(&p->liste, indice_sommet);
else {
printf("Erreur");
return 0;
} }
Analyse et programmation 2 - Listes, files et piles 36
}
Variantes des listes : les piles
Implémentation basée sur la liste tableau
ELEMENT pile_depiler(PILE * p) {
ELEMENT res ltat ELEMENT resultat;
int indice_sommet;
indice_sommet = liste_nombre_elements(&p->liste) - 1;
resultat = pile_sommet(p);
liste_supprimer(&p->liste, indice_sommet);
return resultat;
}
Variantes des listes : les piles
Implémentation basée sur la liste tableau - Analyse
• Difficulté de programmation ?
• Efficacité d’exécution ?
– Avec des tableaux dynamiques :
Analyse et programmation 2 - Listes, files et piles 38
Avec des tableaux dynamiques :
• Lenteur lors du redimensionnement, surtout avec les grands tableaux.
– Avec des tableaux fixes
• Capacité limitée de la pile
• Sur-occupation de mémoire.
Variantes des listes : les files
Introduction
• Rappel du fonctionnement d’une pile
Opérations : enfiler défiler – Opérations : enfiler, défiler
– Le premier entré est le premier sorti
• First In, First Out : FIFO
Applications pratiques
• Ordonnancement du traitement des achats d’un magasin en ligne.
• Gestion des ordres reçus par un système embarqué
• Gestion des ordres reçus par un système embarqué.
• File d’attente d’une imprimante.
Analyse et programmation 2 - Listes, files et piles 40
• Traitement de signal : implémentation d’un retard numérique.
Variantes des listes : les files
Les opérations
• Initialiseur M difi t
• Modificateurs
– Enfiler (PUSH) : ajoute un élément à l’entrée de la file.
– Défiler (POP) : enlève un élément à la sortie de la file.
• Sélecteurs
– Est vide
– Nombre d’éléments.
Variantes des listes : les files
Implémentation basée sur la liste tableau
#ifndef __FILE_H_
#define __FILE_H_
#include "ListeTableauDynamique.h"
typedef struct {
LISTE_TABLEAU liste;
} FILE_TABLEAU;
void file_initialiser(FILE_TABLEAU * f);
void file enfiler(FILE TABLEAU * f, ELEMENT e);
Analyse et programmation 2 - Listes, files et piles 42
o d e_e e ( _ U , e);
ELEMENT file_defiler(FILE_TABLEAU * f);
int file_vide(FILE_TABLEAU * f);
int file_nombre_elements(FILE_TABLEAU * f);
#endif
Variantes des listes : les files
Implémentation basée sur la liste tableau
void file_initialiser(FILE_TABLEAU * f) {
liste initialiser(&f >liste) liste_initialiser(&f->liste);
}
int file_vide(FILE_TABLEAU * f) {
return file_nombre_elements(f) == 0;
}
int file_nombre_elements(FILE_TABLEAU * f) {
{
return liste_nombre_elements(&f->liste);
}
Implémentation basée sur la liste tableau
void file_enfiler(FILE_TABLEAU * f, ELEMENT e) {
liste ajo ter(&f >liste e) liste_ajouter(&f->liste, e);
}
ELEMENT file_defiler(FILE_TABLEAU * f) {
ELEMENT resultat;
resultat = liste_element(&f->liste, 0);
liste_supprimer(&f->liste, 0);
return resultat;
Analyse et programmation 2 - Listes, files et piles 44
etu esu tat;
}
Variantes des listes : les files
Implémentation basée sur la liste tableau - Analyse
• Difficulté de programmation ?
• Efficacité d’exécution ?
– Opération défiler :
• Décalage des éléments de la liste.
• Opération très coûteuse lorsque la file devient grande.Opé at o t ès coûteuse lo sque la le dev e t g a de.
– Avec des tableaux dynamiques :
• Lenteur lors du redimensionnement, surtout avec les grands tableaux.
– Avec des tableaux fixes
• Capacité limitée de la pile
• Sur-occupation de mémoire.
Les listes chaînées
Introduction
• Limitations des listes tableaux
Taille fi e – Taille fixe
– Coût élevé des opérations entrainant un déplacement des éléments.
– Coût proportionnel à la taille de la liste.
– Inapproprié pour de très grandes listes.
• Alternative
– Les listes chaînées
Analyse et programmation 2 - Listes, files et piles 46
Les listes chaînées.
– Autre façon de représenter les listes en mémoire.
Structures de donnée récursives
Introduction – Rappel sur la récursivité
• Formulation récursive d’une fonction
– Une fonction récursive est une fonction qui s’appelle elle-même – Une fonction récursive est une fonction qui s appelle elle-même.
• Exemple : définition récursive de la factorielle
U0= 1 Un= n * Un-1
• Mise en œuvre
long factorielle(long n) {
if (n == 0) return 1;
else
return n * factorielle(n - 1);
}
Introduction
• Structure de données récursive
Une str ct re de données q i se référence elle même – Une structure de données qui se référence elle-même.
• Exemple : définition récursive d’une liste
– Une listec’est
• Soit vide.
• Soit une valeur, suivie d’une autre liste.
– Ce qui peut s’écrire
Liste ::= {} | { Valeur, Liste }
Analyse et programmation 2 - Listes, files et piles 48
{} | { , }
– Cette définition s’appuie donc récursivement sur elle-même.
• Illustration
{}
{ 0, { 1, { 2, { 3, { 4, {} } } } } }
TDA Pile chaînée
Déclaration du type de données en langage C typedef double ELEMENT;
struct CELLULE_PILE_CHAINEE {
ELEMENT element;
struct CELLULE_PILE_CHAINEE * suivant;
};
typedef struct {
struct CELLULE_PILE_CHAINEE * sommet;
} PILE_CHAINEE;
TDA Pile chaînée
Représentation en mémoire - fonctionnement
• Empilage de 10, 20, 30
CELLULE element: 30 suivant
CELLULE element: 10 suivant: NULL CELLULE
element: 20 suivant CELLULE
element: 30 suivant
CELLULE element: 10 suivant: NULL CELLULE
element: 20 suivant
Analyse et programmation 2 - Listes, files et piles 50
PILE_CHAINEE sommet: NULL PILE_CHAINEE sommet PILE_CHAINEE sommet
TDA Pile chaînée
Représentation en mémoire – fonctionnement par étape - empilage
CELLULE
• Empilage de 10, 20, 30
PILE_CHAINEE sommet: NULL
CELLULE element: 10 suivant: NULL
PILE_CHAINEE sommet PILE_CHAINEE
Sommet: NULL
PILE_CHAINEE
CELLULE element: 10 suivant: NULL
PILE_CHAINEE
CELLULE element: 20 suivant
PILE_CHAINEE CELLULE element: 30 suivant
CELLULE element: 10 suivant: NULL
PILE_CHAINEE
CELLULE element: 20 suivant
Représentation en mémoire – fonctionnement par étape - dépilage
• Dépilage de 30, 20, 10
CELLULE element: 30 suivant
CELLULE element: 10 suivant: NULL
PILE_CHAINEE sommet
CELLULE element: 20 suivant
CELLULE element: 30 suivant
CELLULE element: 10 suivant: NULL
PILE_CHAINEE sommet
CELLULE element: 20 suivant
Analyse et programmation 2 - Listes, files et piles 52
CELLULE element: 10 suivant: NULL
PILE_CHAINEE sommet
CELLULE element: 20 suivant
CELLULE element: 10 suivant: NULL
PILE_CHAINEE sommet: NULL
TDA Pile chaînée
Opérations
void pile_initialiser(PILE_CHAINEE * pile);
int pile_vide(PILE_CHAINEE * pile);
int pile nombre element(PILE CHAINEE * pile) int pile_nombre_element(PILE_CHAINEE * pile);
void pile_empiler(PILE_CHAINEE * pile, ELEMENT e);
ELEMENT pile_depiler(PILE_CHAINEE * pile);
TDA Pile chaînée
Opérations
void pile_initialiser(PILE_CHAINEE * pile) {
pile->sommet = NULL;
}
int pile_vide(PILE_CHAINEE * pile) {
return pile->sommet == NULL;
}
Analyse et programmation 2 - Listes, files et piles 54
TDA Pile chaînée
Opérations
void pile_empiler(PILE_CHAINEE * pile, ELEMENT e) {
t t CELLULE PILE CHAINEE * ll ll l struct CELLULE_PILE_CHAINEE * nouvelle_cellule;
// Allocation d'une nouvelle cellule
nouvelle_cellule = (struct CELLULE_PILE_CHAINEE *) malloc(sizeof(struct CELLULE_PILE_CHAINEE));
// mémoriser la valeur de l'élément empilé nouvelle_cellule->element = e;
// Placer la pile actuelle après la nouvelle cellule nouvelle_cellule->suivant = pile->sommet;
// Le nouvel élément est le nouveau sommet de la pile pile->sommet = nouvelle_cellule;
}
Opérations
ELEMENT pile_depiler(PILE_CHAINEE * pile) {
struct CELLULE_PILE_CHAINEE * cellule_depilee;
ELEMENT resultat;
if (!pile_vide(pile)) {
// Dépilage du sommet de la pile cellule_depilee = pile->sommet;
// Le nouveau sommet est la suite de la cellule depilee pile->sommet = pile->sommet->suivant;
// La valeur depilee est la valeur de la cellule depilee resultat = cellule_depilee->element;
// Liberation de la memoire
Analyse et programmation 2 - Listes, files et piles 56
// Liberation de la memoire free(cellule_depilee);
} else {
printf("Erreur\n");
resultat = 0;
}
return resultat;
}
TDA Pile chaînée
Opérations
int pile_nombre_element(PILE_CHAINEE * pile) {
{
struct CELLULE_PILE_CHAINEE * courant;
int nombre = 0;
courant = pile->sommet;
while (courant != NULL) {
nombre++;
courant = courant->suivant;
}
return nombre;
}
TDA Pile chaînée
Analyse
• Avantages
Espace mémoire tilisé en fonction d besoin – Espace mémoire utilisé en fonction du besoin.
– Implémentation efficace, même pour de très grandes piles.
• Inconvénients
– L’allocation et la libération de mémoire sont des opérations assez coûteuses.
– Risque de fragmentation de la mémoire.
– Le temps nécessaire à une allocation est très variable
Analyse et programmation 2 - Listes, files et piles 58
Le temps nécessaire à une allocation est très variable.
• Inapproprié pour des applications critiques en temps.
TDA File chaînée
Principe
• On conserve un pointeur sur le début et sur la fin.
E fil à l fi
• Enfilage à la fin.
• Défilage au début.
TDA File chaînée
Déclaration du type de données en langage C
typedef double ELEMENT;
struct CELLULE_FILE_CHAINEE {
ELEMENT element;
struct CELLULE_FILE_CHAINEE * suivant;
};
typedef struct
Analyse et programmation 2 - Listes, files et piles 60
typedef struct {
struct CELLULE_FILE_CHAINEE * debut;
struct CELLULE_FILE_CHAINEE * fin;
} FILE_CHAINEE;
TDA File chaînée
Représentation en mémoire – fonctionnement de l’enfilage
• Enfilage 10, 20, 30
CELLULE element: 10 suivant: NULL
CELLULE element: 20 suivant: NULL CELLULE
element: 10 suivant
CELLULE element: 30 suivant: NULL CELLULE
element: 20 suivant CELLULE
element: 10 suivant
CELLULE element: 30 suivant: NULL CELLULE
element: 20 suivant
PILE_CHAINEE debut: NULL
suivant: NULL
FILE_CHAINEE debut
suivant: NULL
suivant suivant suivant: NULL
FILE_CHAINEE debut
suivant suivant suivant: NULL
TDA File chaînée
Représentation en mémoire – fonctionnement de l’enfilage
• Enfilage de 10, 20, 30
FILE_CHAINEE debut: NULL fin: NULL
CELLULE element: 10 suivant: NULL
FILE_CHAINEE debut fin
Analyse et programmation 2 - Listes, files et piles 62
CELLULE element: 10 suivant: NULL
FILE_CHAINEE debut fin
CELLULE element: 20 suivant: NULL CELLULE
element: 10 suivant
CELLULE element: 30 suivant: NULL CELLULE
element: 20 suivant CELLULE
element: 10 suivant: NULL
FILE_CHAINEE debut fin
CELLULE element: 20 suivant: NULL CELLULE
element: 10 suivant
TDA File chaînée
Représentation en mémoire – fonctionnement du défilage
• Defilage de 10, 20, 30
CELLULE CELLULE
element: 10 suivant: NULL
FILE_CHAINEE debut fin
CELLULE element: 20 suivant: NULL CELLULE
element: 10 suivant
CELLULE element: 30 suivant: NULL CELLULE
element: 20 suivant
FILE_CHAINEE debut fin
CELLULE element: 30 suivant: NULL CELLULE
element: 20 suivant
FILE_CHAINEE debut: NULL
CELLULE element: 30 suivant: NULL
Opérations
void file_initialiser(FILE_CHAINEE * file);
int file_vide(FILE_CHAINEE * file);
int file nombre element(FILE CHAINEE * file) int file_nombre_element(FILE_CHAINEE * file);
void file_enfiler(FILE_CHAINEE * file, ELEMENT e);
ELEMENT file_defiler(FILE_CHAINEE * file);
Analyse et programmation 2 - Listes, files et piles 64
TDA File chaînée
Opérations
void file_initialiser(FILE_CHAINEE * file) {
file->debut = NULL;
file->fin = NULL;
}
int file_vide(FILE_CHAINEE * file) {
return file->debut == NULL;
}
TDA File chaînée
Opérations
void file_enfiler(FILE_CHAINEE * file, ELEMENT e) {
t t CELLULE FILE CHAINEE * ll ll l struct CELLULE_FILE_CHAINEE * nouvelle_cellule;
// Allocation d'une nouvelle cellule
nouvelle_cellule = (struct CELLULE_FILE_CHAINEE *) malloc(sizeof(struct CELLULE_FILE_CHAINEE));
// mémoriser la valeur de l'élément empilé nouvelle_cellule->element = e;
nouvelle_cellule->suivant = NULL;
if (file->fin != NULL)
// Placer le nouvel élément à la fin file->fin->suivant = nouvelle_cellule;
else
Analyse et programmation 2 - Listes, files et piles 66
// Premier element, c'est aussi le debut file->debut = nouvelle_cellule;
// La nouvelle cellule est à la fin file->fin = nouvelle_cellule;
}
TDA File chaînée
Opérations
ELEMENT file_defiler(FILE_CHAINEE * file) {
struct CELLULE_FILE_CHAINEE * cellule_defilee;
ELEMENT resultat;
if (!file_vide(file)) {
// Défilage du debut de la file cellule_defilee = file->debut;
// Le nouveau debut est la suite de la cellule defilee file->debut = file->debut->suivant;
// La valeur defilee est la valeur de la cellule defilee resultat = cellule_defilee->element;
// Liberation de la memoire // Liberation de la memoire free(cellule_defilee);
} else {
printf("Erreur\n");
resultat = 0;
}
Opérations
int file_nombre_element(FILE_CHAINEE * file) {
{
struct CELLULE_FILE_CHAINEE * courant;
int nombre = 0;
courant = file->debut;
while (courant != NULL) {
nombre++;
courant = courant->suivant;
}
return nombre;
Analyse et programmation 2 - Listes, files et piles 68
}
TDA Liste chaînée
Introduction
• La file ressemble fortement à une liste.
P bt i l TDA li t il ffit d’ j t l
• Pour obtenir le TDA liste, il suffit d’y ajouter quelques opérations :
ELEMENT liste_element(LISTE_CHAINEE * liste, int position);
void liste_inserer(LISTE_CHAINEE * liste, int position, ELEMENT e);
void liste_supprimer(LISTE_CHAINEE * liste, int position);
• L’implantation de ces opérations se fait de façon similaire. p p ç
Structures chaînées
Optimisations
• Compteur d’élément
Il est possible d’intégrer n compte r d’éléments dans la – Il est possible d’intégrer un compteur d’éléments dans la
structure.
– Améliore les performances des opérations nécessitant le nombre d’éléments.
• Recyclage des blocs alloués
– L’allocation et la libération des blocs est coûteuse en temps.
– Il est possible de construire une liste globale des blocs libérés.
Analyse et programmation 2 - Listes, files et piles 70
p g
– Utilisation prioritaire de ces blocs en réserve avant toute nouvelle allocation.
Structures dynamiques et systèmes critiques
Recommandations
• En raison de la fragmentation de la mémoire
L’allocation d namiq e pe t écho er après des millions de s ccès – L’allocation dynamique peut échouer après des millions de succès.
– Les temps d’allocation sont en général peu prévisibles.
• Utilisation des structures dynamiques
– Déconseillée, voire même interdite, pour les systèmes critiques.
– Exemples
• Systèmes vitaux dans le domaine médical
• Automobile
• Automobile
• Spatial
– Dans ces domaines, l’allocation dynamique peut être utilisée seulement pendant les phases d’initialisation du logiciel.
Listes doublement chaînées
• Intérêt
Simplification des algorithmes nécessitant l’élément précédent – Simplification des algorithmes nécessitant l’élément précédent
• Ex: suppression.
– Parcours efficace dans les deux sens.
CELLULE element: 10 suivant: NULL
CELLULE element: 20 suivant: NULL CELLULE
element: 10 suivant
CELLULE element: 30 suivant: NULL CELLULE
element: 20 suivant
Analyse et programmation 2 - Listes, files et piles 72
suivant: NULL
LISTE_DOUBLE_CHAINEE debut
fin
suivant: NULL suivant
precedent:NULL
suivant: NULL precedent suivant
precedent
Autres structures couramment utilisées
Arbres
• Représentation de hiérarchies.
Une cell le pointe ers 2 o pl sie rs cell les filles – Une cellule pointe vers 2 ou plusieurs cellules filles.
– Une cellule n’est pointée qu’une seule fois.
Autres structures couramment utilisées
Graphes
• Représentation de structures complexes.
Une cell le pointe ers ne o pl sie rs cell les – Une cellule pointe vers une ou plusieurs cellules.
– Une cellule est pointée par une ou plusieurs cellules.
Analyse et programmation 2 - Listes, files et piles 74
Qu’avons-nous appris ?
• Les TDA Liste, File et Pile.
L’i lé t ti t bl
• L’implémentation par tableau.
• L’implémentation avec les structures de données
récursives.
Vos questions
Analyse et programmation 2 - Listes, files et piles 76