Cours SD Koffi Dagou - Partie 1

Vous aimerez peut-être aussi

Vous êtes sur la page 1sur 36

COURS D’ALGORITHME ET STRUCTURE DE DONNEES

AVEC LE LANGAGE C

Dr KOFFI Dagou Dangui Augustin Sylvain Legrand


Assistant
dagousylvain@gmail.com
1
Introduction

1.1 Objectifs du cours


L'objectif du cours est de présenter les structures de données et les algorithmes permettant de
les manipuler. Il s’agira de :

 Fournir aux étudiants une compréhension solide des concepts fondamentaux des
algorithmes et des structures de données, y compris les types de données, les opérations
de base et les principes de conception.
 Apprendre aux étudiants à choisir et à utiliser les structures de données les plus
appropriées pour résoudre différents types de problèmes, en tenant compte de
l'efficacité et des exigences du problème.
 Enseigner aux étudiants comment analyser la complexité temporelle et spatiale des
algorithmes à l'aide de la notation Big O, et comment prédire l'impact des choix de
structures de données sur les performances.
 Permettre aux étudiants d’apprendre et de mettre en pratique les concepts de résolution
de problèmes spécifiques du monde réel avec la mise en œuvre d'algorithmes et de
structures de données en utilisant des étapes logiques et des méthodes de décomposition
de problèmes.
 Apprendre aux étudiants des techniques d'optimisation pour améliorer l'efficacité des
algorithmes et des structures de données, en tenant compte de facteurs tels que le temps
d'exécution et l'utilisation de la mémoire.

Nous aurons une introduction générale aux structures de données. Ensuite, nous allons fournir
les outils nécessaires pour l'organisation et la manipulation des données dans les structures de
données. Enfin, nous allons aborder quelques algorithmes avancés et étudier leur complexité.

2
1.2 Généralités sur les structures de données

1.2.1 Rappel sur le rôle des ordinateurs


Un ordinateur est un appareil ou une machine qui permet de réaliser, d’exécuter des opérations,
des calculs, des tâches. De ce fait, même une simple calculatrice est un ordinateur (figure 1).
Un ordinateur n'est pas à lui seul capable de résoudre des problèmes. Ce sont les algorithmes
qui sont chargés de résoudre ou faire résoudre les problèmes aux ordinateurs en leur donnant
les taches à exécuter.

"A l’origine de toute erreur attribuée à l’ordinateur, vous trouverez au


moins deux erreurs humaines. Dont celle consistant à attribuer l’erreur à
l’ordinateur."

Figure 1 : Calculatrice

1.2.2 Définition (Algorithme)


Un algorithme est la description d'une suite d'étapes permettant d'obtenir un résultat à partir
d'éléments fournis en entrée. Pour qu'un algorithme puisse être exécuté par un ordinateur, il
faut le transformer en langage machine (compilation).

3
Figure 2 : Représentation d'un Algorithme

Mise en œuvre d'une application

Plusieurs étapes sont nécessaires pour mettre en œuvre une application :

Etape 1 : Définition du problème

Il s'agit de déterminer toutes les informations disponibles et la forme des résultats désirés.

4
Etape 2 : Analyse du problème

Elle consiste à trouver le moyen de passer des données aux résultats. Dans certains cas, on peut
être amené à faire une étude théorique. Le résultat de l'étape d'analyse est un algorithme.

Etape 3 : Ecriture d'un algorithme avec un langage de description algorithmique

Une fois qu'on trouve le moyen de passer des données aux résultats, il faut être capable de
rédiger une solution claire et non ambiguë. Comme il est impossible de le faire en langage
naturel pour les raisons que nous donnerons par la suite, l'existence d'un langage algorithmique
s'impose.

Etape 4 : Traduction de l'algorithme dans un langage de programmation

Les étapes 1, 2 et 3 se font sans le recours de la machine. Si on veut rendre l'algorithme pratique,
il faudrait le traduire dans un langage de programmation. Nous dirons alors qu'un programme
est un algorithme exprimé dans un langage de programmation.

Etape 5 : Mise au point du programme

Quand on soumet le programme à la machine, on peut être confronté à deux types de


problèmes :

- la machine corrige l'orthographe, c'est ce qu'on appellera syntaxe dans le jargon de la


programmation.

- la machine traduit le sens exprimé par le programme.

Si les résultats obtenus sont ceux attendus, la mise au point du programme se termine.

Si nous n'obtenons pas de résultats, on dira qu'il y a existence des erreurs de logique. Le
programme peut nous répondre comme suit :

- aucun résultat

- des résultats inattendus

- une partie des résultats

5
Dans ce cas, il faut revoir en priorité si l'algorithme a été bien traduit, ou encore est-ce qu'il y a
eu une bonne analyse.

Ce dernier cas est considéré comme grave car il faut tout refaire, c'est à dire la révision de
l'étape d'analyse pour la réécriture de l'algorithme ainsi que sa traduction.

Un algorithme reçoit des données en entrée qu'il manipule pour produire un résultat à la sortie
en ayant effectué des opérations (figure 2). De cette phrase, nous retenons deux choses :
manipulation des données et exécution des opérations. Dans ce cours nous allons nous
intéresser à la manipulation des données.

Pour manipuler les données tout au long de la réalisation (le temps d'exécution) de l'algorithme,
elles doivent être stockées dans la mémoire vive de l'ordinateur (RAM). De plus, les données
manipuler peuvent varier. On parle alors de variable.

1.2.3 Variables (SD élémentaire)


Dans un programme informatique, on va avoir en permanence besoin de stocker provisoirement
des valeurs. Il peut s’agir de données issues du disque dur, fournies par l’utilisateur (entrées au
clavier). Il peut également s’agir de résultats obtenus par le programme, intermédiaires ou
définitifs. Ainsi, au sein du même algorithme, les valeurs d'une variable sont amenées à
changer. Les données des variables peuvent être de plusieurs types : elles peuvent être des
nombres, du texte, des dates, des images, etc.

Une variable est une boîte ou case de la mémoire, que le programme réserve et repérée par un
nom. Pour avoir accès au contenu de la boîte, il suffit de la désigner par son nom. Dans la
réalité, la case mémoire est repérée par une adresse. C'est dans le programme que la variable
porte un nom. C'est l'ordinateur qui fait le lien entre le nom et l'adresse lors de la compilation.
Une variable est donc identifiée par :

⎯ Un nom
⎯ Un type
⎯ Une valeur
⎯ Une adresse (facultative car c'est l'ordinateur qui s'en occupe)

6
Les types de données les plus couramment utilisés sont, les entiers, les réels, les chaines de
caractère, les booléen, etc. la mémoire réservée dépend du type de la variable (tableau 1).

Tableau 1 : Type de variable en algorithme

Type Codage Valeurs


Caractère 2 octets 'a', 'A', '"', ' '
Entier 4 octets 2147418112
Réel 8 octets 134.456, -45E-16
Booléen 1 octet False, True
Chaîne de caractères Selon le nombre de caractères "INF1563", "M1 Math"
Date 8 octets 05/04/2022

En langage algorithmique, on utilise le symbole ← pour indiquer qu'une valeur est affectée à

une variable :
a←1
affectation de la valeur 1 à la variable a
la variable a reçoit la valeur 1

a 1

Ces types de variables sont suffisant pour manipuler les données de base. Cependant, lorsqu'il
faut manipuler des données complexes et structurées, il faut des types de variables plus évolués.
C'est à ce niveau qu'intervient les structures de données.

1.2.4 Définition des Structures de données


La plupart des bons algorithmes fonctionnent grâce à une organisation intelligente des données.
Une structure de données est une représentation structurée des données. Elle permet de mieux
organiser et stocker les données qui sont généralement liées. Le but est de faciliter l'accès et la
manipulation. Par exemple, les noms des étudiants peuvent être stocker dans la structure de
données "Tableau".

7
1.2.5 Importance des Structures de données
Les structures de données sont essentielles pour gérer efficacement de grandes quantités de
données, telles que les informations conservées dans des bases de données ou des services
d’indexation. La maintenance correcte des systèmes de données nécessite l’identification de
l’allocation de la mémoire, des interrelations entre les données et des processus de données,
autant d’éléments auxquels les structures de données contribuent.

En outre, il est non seulement important d’utiliser des structures de données, mais aussi de
choisir la structure de données appropriée pour chaque tâche. Le choix d’une structure de
données inadaptée pourrait entraîner des temps d’exécution lents ou un code non réactif.
Quelques facteurs à prendre en compte lors du choix d’une structure de données incluent le
type d’informations qui seront stockées, l’emplacement des données existantes, la manière dont
les données doivent être triées et la quantité de mémoire à réserver pour les données.

Pour gérer le milliard de pages web indexées par google ou les informations des habitants d'un
pays comme la chine (1,3 milliard d'habitants) les systèmes informatiques doivent prévoir la
taille de la mémoire à allouer et la disposition des données. Les types de variables élémentaires
sont inefficace pour de tels traitements. Par exemple, prenons la gestion d'une cérémonie avec
200 invités. Connaitre le nombre n'est pas suffisant, vous devez avoir des informations sur le
type d'invités, est-ce une cérémonie pour adulte ou pour enfant ? (Prendre l'analogie des
tréteaux) y a-t-il des invités de marque ? etc. voilà autant d'information pour prévoir la
disposition des chaises et tables, des couverts, etc.

1.2.6 Usage des Structures de données


Les structures de données contiennent des informations sur des valeurs, des données, des
relations entre les données et les fonctions qui peuvent être appliquées aux données. Il existe
de nombreuses structures de données qui peuvent être utilisées dans des domaines variés.
Cependant les structures de données qui seront étudiées dans ce cours sont les suivants :

Enregistrement

La Structure de données Enregistrement sert à rassembler au même endroit les informations sur
une même entité. Par exemple, les informations sur les étudiants de l'université sont organisées
dans une variable de type Enregistrement.

8
Pile et File

La pile permet de stocker des éléments et les récupérer dans l'ordre inverse. L’élément qui est
stocké à la fin sera le premier à être récupéré de la pile.

Un éditeur de texte tel que Notepad ou Microsoft Word utilise une structure de données Pile
pour accomplir des tâches d’annulation dans son éditeur. Un autre bon exemple de pile est la
gestion de l'historique dans le navigateur de votre ordinateur portable ou de votre système.

Liste Chaînée

Les listes chainées stockent des collections d’éléments dans un ordre linéaire où chaque élément
est lié au suivant.

Par exemple, lorsqu’on crée une liste de lecture sur un smartphone, elle fonctionne sur le
concept de la liste chainée. Ces chansons sont jouées une par une, elles sont connectées et on
peut passer de la chanson trois à la chanson quatre.

Tableau

La première structure de données à apprendre en programmation et la structure de données la


plus courante et la plus utilisée dans de nombreuses applications.

Pointeur

Le pointeur n'est pas à proprement dit une structure de données. Il constitue plutôt une référence
vers une zone mémoire. Il est utilisé pour la gestion dynamique de la mémoire.

Arbre

Un arbre stocke une collection d’éléments de manière abstraite et hiérarchique. Chaque nœud
est lié à d’autres nœuds et peut avoir plusieurs sous-valeurs, également appelées enfants. Il est
utilisé en intelligence artificielle et data analyses.

9
2
Structures de données Tableau

2.1 Définition
On appelle tableau une variable composée de données de même type, stockée de manière
contiguë en mémoire (les unes à la suite des autres). Un tableau est donc une suite de cases
(espace mémoire) de même taille. La taille de chacune des cases est conditionnée par le type
de donnée que le tableau contient.

2.2 Déclaration des tableaux

Nom_tableau : tableau[1..N] de type ;


Nom : tableau[1..100] de chaine de caractère ;

2.3 Manipulation
1 2 3 4 5 6 7
25
On accède aux par leurs indices éléments. Nom_tableau[indice]. On manipule les tableaux à
l'aide des boucles.

Exemple :

Déclarons un tableau de l'enregistrement de 15 notes des étudiants.

Note : tableau[1..15] de réel ;


Pour avoir accès à la note 5, on fait Note[5]

Afficher (Note[5])  19

Note[5]  25

Afficher (Note[5]) 25

10
NB : Dans les langages de programmation les indices des tableaux commencent généralement
par 0.

Exemple (Langage C)

REPRESENTATION PHYSIQUE

Lors de la déclaration d'un tableau, une zone mémoire lui sera réservée. Elle sera utilisée pour
le stockage de ses données. La taille de cette zone en octets est la multiplication de la taille du
tableau par la taille du type de ses éléments (un tableau de trois entiers sera représenté par six
octets : chaque entier est codé sur deux octets).

Un tableau T correspond à l'adresse mémoire de son premier élément (T=&T[0]). Il s'agit de la


première cellule de la zone mémoire qui lui est réservé.

Exemple

11
Afficher (T[0])  a

Afficher (&T[0])  100

Initialisation

Syntaxe :

Type Identificateur [Taille constante] = {Valeur1, Valeur2,…,Valeurn};

12
0 1 2
a 0 1.5 3

0 1 2
b 1

0 1 2
c x y

0 1 2
d 4 6 8

Remarque :
Un tableau peut être totalement ou partiellement initialisé.

LECTURE ET AFFICHAGE

Les éléments d'un tableau sont à lire et à afficher élément par élément.
Exemple :

Remarque :
Lors de la lecture ou de l'affichage d'un tableau, le compilateur C n'empêche pas un
dépassement des limites (la taille) du tableau. Une vérification par le programmeur est alors
importante.
AFFECTATION

13
L'affectation de valeurs aux éléments d'un tableau se fait également individuellement (comme
pour la lecture et l'affichage).
Exemple:

Remarques :
L’affectation d’un tableau B à un autre tableau A se fait élément par élément. Une
affectation "brutale" de B à A (A=B) n'est pas possible.
L'affectation élément par élément d'un tableau B à un autre tableau A (A[i]=B[i]) réalise
une copie de B dans A.

14
COMPARAISON DE DEUX TABLEAUX
La comparaison des éléments de deux tableaux doit se faire élément par élément.
Exemple :

15
TABLEAUX A PLUSIEURS DIMENSIONS
DECLARATION
Note : tableau[1..n, 1..m, ... , 1..k] de réel ;
Syntaxe :
Type Identificateur [Taille1] [Taille2] … [Taille n] ;
Taillei est la taille de la dimension i. Elle doit être une constante définie avant
ou au moment de la déclaration.
Un élément d'un tableau t à n dimensions est repéré par ses indices, sous
forme t[i1][i2]…[in].

Exemple :

16
17
3
Enregistrements
Supposons que nous voulons enregistrer les informations des étudiants de M1. Les informations
que nous voulons enregistrer sont : le nom, le prénom, la date de naissance, la taille, boursier
ou non. Comment nous allons procéder, quelles sont les variables que nous allons utiliser ?

3.1 Définition
Les enregistrements (également nommés types structurés) sont des structures de données dont
les éléments constitutifs peuvent être de type différent et qui se rapportent à la même entité.
L'avantage d'un enregistrement est de regrouper des informations sémantiquement liées pour
éviter de multiplier les variables et bien faire apparaitre la logique du traitement.

Jusqu'à présent, nous n'avons utilisé que des types primitifs (caractères, entiers, réels, chaînes)
et des tableaux de types primitifs. Mais nous pouvons créer nos propres types puis déclarer des
variables ou des tableaux d'éléments de ce type. Pour créer des enregistrements, il faut déclarer
un nouveau type, basé sur d'autres types existants.

3.2 Déclaration
On déclare une structure de données de la manière suivantes :

TYPE
Nom_enregistrement = Enregistrement
Champ1 : type1 ;
Champ2 : type2 ;
Fin Enregistrement

Prenons l'exemple de l'enregistrement des informations d'un étudiant de M1 Maths. Nous


aurons :

18
TYPE
Tetudiant = Enregistrement
Nom : Chaine de caractère ;
Prénom : Chaine de caractère ;
Date_Naissance : Date ;
Taille : Réel ou entier ;
Boursier : Booléen ;

Fin Enregistrement

Une fois qu'on a défini un enregistrement, on peut déclarer des variables enregistrements
exactement de la même façon que l'on déclare des variables d'un type primitif.

Variables
Nom_variable : nom_enregistrement ;
Exemple

Variables
Etudiant1, Etudiant2 : Tetudiant ;

3.3 Manipulation des enregistrements


La manipulation d'un enregistrement se fait au travers de ses champs. Comme pour les tableaux,
il n'est pas possible de manipuler un enregistrement globalement, sauf pour affecter un
enregistrement à un autre de même type. Par exemple, pour afficher un enregistrement il faut
afficher tous ses champs uns par uns. Il n'est donc pas possible de faire ;

Afficher (Etudiant1)

Pour avoir accès à un champs d'un enregistrement, il faut mettre un "." entre le nom de

l'enregistrement et le nom du champ. Par exemple :

Etudiant1.Nom

19
3.4 Tableau d'enregistrement
Supposons que nous ayons maintenant 500 étudiants que nous devons enregistrer. Il serait
fastidieux de créer 500 variables de type Tetudiant. On va créer un tableau regroupant toutes
les personnes du groupe. Il s’agit alors d’un tableau d’enregistrements.

Variables
Nom_variable : tableau[1..N] de nom_enregistrement ;

Exemple

Variables
Etudiant : tableau[1..500] de Tetudiant ;
Cela représente :

Nom Prénom Date de naissance Taille Boursier


1
2

500
Pour accéder au nom du deuxième étudiant on fait :

Etudiant[2].Nom
et pas

Etudiant.Nom[2]

3.5 Déclaration de l’enregistrement en langage C


Une structure est un assemblage de variables qui peuvent avoir différents types. Contrairement
aux tableaux qui vous obligent à utiliser le même type dans tout le tableau, vous pouvez créer
une structure comportant des variables de plusieurs types, long , char , int et double à la fois.
Les structures sont généralement définies dans les fichiers .h.

Une structure, est définit par mot clé struct, suivi de nom de la structure.

La structure en C est définie de la manière suivante :

20
struct NomDeVotreStructure
{
int variable1;
int variable2;
int autreVariable;
double nombreDecimal;
char nomCaractere ;
};

Exemple

Supposons une structure Personne qui stocke diverses informations sur une personne :

struct Personne
{
char nom[100];
char prenom[100];
char adresse[1000];

int age;
int etudiant; // Booléen : 1 = etudiant, 0 = non etudiant
};

21
4
Pointeurs

4.1 Notions de pointeur


Comment fonctionne une variable ?

En réalité une variable est une zone de la mémoire réservée. La mémoire d'un ordinateur est
une sorte de casier avec plusieurs compartiments référencés par leurs adresses.

Un pointeur est une adresse mémoire : il permet de désigner directement une zone de la
mémoire et donc l'objet dont la valeur est rangée à cet endroit. Un pointeur est souvent typé de
manière à préciser quel type d'objet il désigne dans la mémoire.

4.2 Déclaration
On déclare un pointeur en indiquant le type de l'élément pointé, puis on met * avant le nom du
pointeur. On peut déjà l'initialiser à null. Dans le programme, il ne faut plus ajouter * au nom
du pointeur en l'utilisant.

Type *nomPointeur ;
nomPointeur = Null ;
L'adresse d'une variable s'obtient en précédant son nom de &.

Exemple :

Prix : Entier ; Adresse Valeur


Entier *p ;
Prix @408200 2000
Prix = 2000
P = &Prix P @632000 @408200

22
int a=10;
int * p;

p = &a;
ou

int *p;
int p= &a;

Initialisation du pointeur à NULL

int *p = NULL; /* Un pointeur nul */

4.3 Propriétés des pointeurs


Un pointeur qui reçoit un autre pointeur pointe alors sur la même variable. Un pointeur précédé
de * dans le programme permet d'accéder à la valeur de l'élément pointé.

Exemple :
Prix 2000
P @408200
&Prix @408200
*P 2000
&P @632000

23
5
Piles et Files

Les piles et les files sont des structures de données permettant de représenter, toutes deux, des
ensembles de données. L’ajout d’un élément dans l’ensemble et le retrait d’un élément hors de
l’ensemble se font par des opérations spécialisées, qui assurent

— dans le cas d’une file, les éléments sortent dans le même ordre que celui dans lequel ils sont
entrés (principe du premier entré, premier sorti). Cette stratégie s’appelle FIFO (First In,
First Out) ;

— dans le cas d’une pile, les éléments sortent dans l’ordre inverse de celui dans lequel ils sont
entrés (principe du dernier entré, premier sorti). Cette stratégie s’appelle LIFO (Last In,
First Out).

La tradition veut que les opérations d’ajout et de retrait portent les noms « enfiler » et «
défiler », dans le cas d’une file, et « empiler » et « dépiler », dans le cas d’une pile. Il est
possible de réaliser une file d’éléments de type element avec le type abstrait minimaliste
suivant. La première fonction permet de vider la file F. La deuxième permet de tester si F est
vide. La troisième enfile e dans F. La quatrième défile l’élément le plus ancien de F et le
retourne.

void vider (struct file* F);


bool est_vide (struct file* F);
void enfiler (struct file* F, element e);
element defiler (struct file* F);

De même, il serait possible de réaliser une pile d’élément avec le type abstrait minimaliste
suivant. La première fonction permet de vider la pile P. La deuxième permet de tester si P est
vide. La troisième empile e dans P (au sommet de P). La quatrième dépile l’élément le plus
récent de P (au sommet de P) et le retourne.

24
void vider (struct pile* P);
bool est_vide (struct pile* P);
void empiler (struct pile* P, element e);
element depiler (struct pile* P);

Piles

5.1 Définition
Une pile stocke de manière ordonnée des éléments, mais rend accessible uniquement un seul
d'entre eux, appelé le sommet de la pile. Le dernier élément ajouté est le premier à sortie (figure
3).

Figure 3 : Représentation des piles

5.2 Modélisation d'une pile


Il existe deux manières pour modéliser une pile. Soit par un tableau soit par une liste chainée.
La modélisation par tableau consiste à utiliser un tableau de taille fixe pour insérer les éléments
de la pile. L'ajout d'un élément se fera à la suite du dernier élément du tableau. Le retrait d'un
élément de la pile se fera en enlevant le dernier élément du tableau. De ce fait, il est nécessaire
de connaitre la position du dernier élément de la pile, C'est le sommet de la pile (figure 4).

25
Figure 4 : Modélisation d'une pile avec le sommet

Les invariants ou les propriétés d'une pile sont : le nom de la pile, le sommet, le tableau
d'élément et le type. Après la déclaration de la pile, les opérations qui peuvent être réalisées sur
celle-ci (également appelées primitives de la pile) sont : l'initialisation, le test de pile vide, le
test de pile pleine, l'empilement et le dépilement.

5.3 Déclaration et initialisation d'une pile


Pour construire une pile nous avons besoin d'un tableau de taille fixe et de l'indice du sommet.
La structure de données qui peut regrouper ces deux informations de type différent est
l'enregistrement.

5.3.1 Déclaration

TYPE
Nom_pile = Enregistrement
Const entier taille = 10;
P : tableau [taille] de entiers ;
sommet : entier ;
Fin Enregistrement

En langage C

typedef struct Element Element;


struct Element
{

26
int nombre ; /*La donnée que notre pile stockera*/
Element *suivant ; /*Pointeur vers l’élément suivant de la pile */
};

Exemple :

#include <stdio.h>

#include <stdlib.h>

#include <stdbool.h>

#define TAILLE_MAX 100

struct Pile {
int donnees[TAILLE_MAX];
int sommet;
};

5.3.2 Initialisation
A l'initialisation, le sommet de la pile est égal à zéro.

Initialiser (pile p)
p.sommet = 0;
Fin

Exemple
Pile P; //Création d’une pile nommée P

void initPile(struct Pile *pile) {

27
pile->sommet = -1;
}
5.3.3 Les primitives ou opérations des piles

Test de pile vide

Une pile est vide lorsque le sommet est égal à zéro.

Estvide(pile p)
Si p.sommet = 0 alors
Retourner vrai ;
Sinon
Retourner faux ;
Fin

En langage C

bool estVide(struct Pile *pile) {


return pile->sommet == -1;
}

Test de pile pleine

La pile est pleine lorsque le sommet est égal à la taille N du tableau.

Estpleine(pile p)
Si p.sommet = p.taille alors
Retourner vrai ;
Sinon
Retourner faux ;
Fin

En langage C

28
bool estPleine(struct Pile *pile) {
return pile->sommet == TAILLE_MAX - 1;
}

Empilement

L'empilement consiste à ajouter un élément dans la pile. Ainsi, le nouvel élément se mettra
audessus du sommet actuel et deviendra le nouveau sommet. La pile ne doit pas être pleine.

Empiler(pile p, x)
Si estpleine(p) = faux alors
p.sommet = p.sommet + 1;
p[p.sommet] = x ;
Sinon
Afficher ('pile déjà pleine') ;
Fin

En langage C

void empiler(struct Pile *pile, int valeur) {


if (estPleine(pile)) {
printf("Erreur : la pile est pleine, impossible d'empiler.\n");
return -1; // Une valeur d'erreur, vous pouvez la personnaliser selon
}
pile->donnees[++pile->sommet] = valeur;
}

Dépilement

Le dépilement consiste à enlever un élément de la pile. Du fait de la stratégie LIFO, c'est le


sommet qui peut être enlevé. Ainsi, en retirant un le sommet, c'est la case précédente qui devient
le nouveau sommet. Cependant, il faut s'assurer que la pile n'est pas vide, sinon l'opération
retournera une erreur.

Depiler(pile p)

29
x : entier ;
Si estvide(p) = faux alors
x = p.sommet ;
p.sommet = p.sommet - 1;
retourner x ;
Sinon
Afficher ('pile vide') ;
Fin

En langage C

void depiler(struct Pile *pile) {


if (estVide(pile)) {
printf("Erreur : la pile est vide, impossible de dépiler.\n");
return -1; // Une valeur d'erreur, vous pouvez la personnaliser selon vos
besoins.
}
Printf("La valeur dépilée est %d ", pile->donnees[pile->sommet--]);
}

Vider la pile

Fonction ViderPile(pile):

Initialiser (pile) //Initialisation de la pile

Fin

En langage C

void viderPile(struct Pile *pile) {


pile->sommet = -1;

30
}

Exemple de menu principal

int main() {
struct Pile maPile;
initPile(&maPile);

empiler(&maPile, 10);
empiler(&maPile, 20);
empiler(&maPile, 30);

printf("La pile est vide ? %s\n", estVide(&maPile) ? "Oui" : "Non");


printf("La pile est pleine ? %s\n", estPleine(&maPile) ? "Oui" : "Non");

printf("Éléments de la pile : ");


while (!estVide(&maPile)) {
printf("%d ", depiler(&maPile));
}
printf("\n");

printf("La pile est vide ? %s\n", estVide(&maPile) ? "Oui" : "Non");

return 0;
}

5.4 Files
La file est une structure de données fonctionnant comme la pile. A la différence de la pile, elle
applique la stratégie FIFO (First In, First Out). Le premier élément de la file est traité en
premier.

31
5.4.1 Déclaration

TYPE
Nom_file = Enregistrement
P : tableau [TAILLE_MAX] de entiers ;
debut : entier ;
fin : entier ;
taille : entier ;
Fin Enregistrement

En langage C

struct File {
int donnees[TAILLE_MAX];
int debut; // Indice de début de la file
int fin; // Indice de fin de la file
int taille; // Nombre d'éléments dans la file
};

5.4.2 Initialisation
A l'initialisation, le sommet de la pile est égal à zéro.

Initialiser (file F)
F.debut = 0;
F.fin = 0;
F.taille = 0;
Fin

Exemple
#include <stdio.h>

#include <stdlib.h>

#include <stdbool.h>
32
#define TAILLE_MAX 100

void initFile(struct File *file) {


file->debut = 0;
file->fin = -1;
file->taille = 0;
}
5.4.3 Les primitives ou opérations des files

Test de file vide

Une file est vide lorsque la taille est égal à zéro.

Fonction EstFileVide(file):
Si (file.taille = 0) Alors
Retourner Vrai
Sinon:
Retourner Faux

En langage C

bool estVide(struct File *file) {


return file->taille == 0;
}

Test de file pleine

La file est pleine lorsque le sommet est égal à la taille N du tableau.

Fonction EstFilePleine(file):
Si (file.taille = TAILLE_MAX) Alors:
Retourner Vrai

33
Sinon:
Retourner Faux

En langage C

bool estPleine(struct File *file) {


return file->taille == TAILLE_MAX;
}

Enfilement

Enfiler(file f, x)
Si EstFilePleine(f) = faux alors
f.fin = f.fin + 1
f[f.fin] = x
f.taille = f.taille + 1
Sinon
Afficher ('file déjà pleine') ;
Fin
En langage C

void enfiler(struct File *file, int valeur) {


if (estPleine(file)) {
printf("Erreur : la file est pleine, impossible d'enfiler.\n");
return;
}
file->fin = (file->fin + 1) % TAILLE_MAX;
file->donnees[file->fin] = valeur;
file->taille++;
}

Défilement

Defiler(file f)

34
Si EstFileVide(f) = faux alors
x = f[f.debut]
f.debut = f.debut + 1
f.taille = f.taille - 1
retourner x
Sinon
Afficher ('file déjà vide') ;
Fin

En langage C

int defiler(struct File *file) {


if (estVide(file)) {
printf("Erreur : la file est vide, impossible de défiler.\n");
return -1; // Une valeur d'erreur, vous pouvez la personnaliser
selon vos besoins.
}
int valeur = file->donnees[file->debut];
file->debut = (file->debut + 1) % TAILLE_MAX;
file->taille--;
printf("La valeur défilée est %d ", valeur);
}

Vider la file

Fonction ViderFile(file):
Initialiser (file F) // Initialiser la file
Fin
En langage C

void viderFile(struct File *file) {


file->debut = 0;

35
file->fin = -1;
file->taille = 0;
}

Exemple de menu principal

int main() {
struct File maFile;
initFile(&maFile);

enfiler(&maFile, 10);
enfiler(&maFile, 20);
enfiler(&maFile, 30);

printf("La file est vide ? %s\n", estVide(&maFile) ? "Oui" : "Non");


printf("La file est pleine ? %s\n", estPleine(&maFile) ? "Oui" : "Non");

printf("Éléments de la file : ");


while (!estVide(&maFile)) {
printf("%d ", defiler(&maFile));
}
printf("\n");

printf("La file est vide ? %s\n",


estVide(&maFile) ? "Oui" : "Non");

return 0;
}

36

Vous aimerez peut-être aussi