Vous êtes sur la page 1sur 65

Par: mme Olfa HAMROUNI JEMLI

Chapitre 7: CHAINES DE CARACTERES


Objectif du chapitre: manipuler les chaînes de caractères.
Plan du chapitre:
I. Introduction
II. Opérations élémentaires sur les chaînes de caractères
III. Applications

I. INTRODUCTION
Une chaîne de caractères est considérée comme un tableau de caractères. Elle est
délimitée par 2 guillemets. Une chaîne vide est représentée par 2 guillemets accolés.
La déclaration d'une chaîne de caractères se fait suivant la syntaxe suivante:
<Nom_Variable_Chaine>: chaine [longueur]

II. OPERATIONS ELEMENTAIRES SUR LES CHAINES DE CARACTERES


a. ENTREE ET SORTIE STANDARD DE CHAINES
- Écriture de chaînes
Pour l'écriture de chaînes sur la sortie standard, on utilise la fonction écrire.
- Lecture de chaînes
Pour la lecture des chaînes à partir de l'entrée standard, on utilise la fonction lire.
Exemple:
Ch:chaine (30)
Ecrire ("Donner une chaine de caractères:")
Lire (ch)
Ecrire ("La chaine lue est:", ch)

b. COPIE D'UNE CHAINE DE CARACTERES DANS UNE AUTRE


La fonction Copier_chaine copie le contenu d'une chaîne de caractères (chaine_source)
vers une autre chaîne (chaine_destination).
La sysntaxe est:
Copier_chaine (chaine_destination, chaine_source)
Exemple:
Ch: chaine (30)
Copier_Chaine (ch,"Bonjour")
Ecrire (ch)
 Ce qui va être affiché sur écran est: Bonjour

1 sur 64
Par: mme Olfa HAMROUNI JEMLI

 Il est à signaler qu'il est interdit de remplacer Copier_Chaine (ch,"Bonjour") par ch 

"Bonjour"

c. RECHERCHE DE LA LONGUEUR D'UNE CHAINE

La fonction Longueur_chaine renvoie le nombre de caractères contenus dans une


chaîne.
La syntaxe est:
Longueur_Chaine (chaine)
Exemple:
Ch: chaine (30)
L:entier
Copier_Chaine (ch,"Bonjour")
L  Longueur_Chaine (ch)
Ecrire (L)
 Ce qui va être affiché sur écran est: 7

d. AJOUT DU CONTENU D'UNE CHAINE A UNE AUTRE


Il peut être nécessaire d'ajouter le contenu d'une chaîne de caractères à celui d'une autre
chaîne. Si, par exemple, une chaîne contient un nom de fichier et une autre chaîne un
nom de dossier, il est possible, en les rassemblant, de donner le chemin d'accès au
fichier. Ce mécanisme d'addition de chaînes porte, en algorithmique et programmation,
le nom de concaténation de chaînes de caractères. La fonction qui assure ce mécanisme
est: Concaténer_Chaine. Sa syntaxe est:
Concaténer_Chaine (chaine_Destination, chaine_source)
Le résultat de la concaténation va se trouver au niveau de la chaîne destination.
Exemple:
Nom_Fichier: chaine (14)
Extension: chaine (5)
Copier_Chaine (Nom_Fichier,"Projet")
Copier_Chaine (extension,".doc")
Concaténer_Chaine (Nom_Fichier, extension);
Écrire ("Le nom complet du fichier est: ", Nom_Fichier);
 Ce qui va être affiché sur écran est: Projet.doc

e. COMPARAISON DE DEUX CHAINES DE CARACTERES

2 sur 64
Par: mme Olfa HAMROUNI JEMLI

Pour tester l'égalité de deux chaînes, il y a la fonction Comparer_Chaine. Cette dernière


détermine en plus, si une chaîne et plus grande qu'une autre, et ceci, par exemple, à des
fins de tri. Cette fonction admet 2 paramètres chaine1 et chaine2.
Comparer_Chaine est une fonction qui retourne:
- 0 si chaine1=chaine2
- une valeur positive si chaine1 > chaine2
- une valeur négative si chaine1 < chaine2.
Exemple:
S1, S2: chaine(30)
Écrire ("Saisir 2 chaines")
Lire (S1, S2)
Si (non Comparer_Chaine (S1, S2)) alors
Ecrire ("Les 2 chaînes sont égales")
Sinon écrire ("les 2 chaînes ne sont pas égales")
Fin si

f. VERIFICATION DU TYPE DE CARACTERE


Il existe des fonctions qui permettent de vérifier le type d'un caractère (majuscule,
minuscule, chiffre, etc.). Le tableau ci-dessous résume quelques fonctions:

Fonction Rôle Valeur de retour


Estalnum (caractère) retourne:
Vérifie si le caractère fourni en
- 0 si le caractère n'est pas
Estalnum paramètre est un caractère
alphanumérique
alphanumérique (chiffre, lettre)
- <> 0 sinon
Estalpha (caractère) retourne:
Vérifie si le caractère fourni en
- 0 si le caractère n'est pas
Estalpha paramètre est un caractère
alphabétique
alphabétique (lettre)
- <> 0 sinon
EstChiffre (caractère) retourne:
Vérifie si le caractère fourni en
- 0 si le caractère n'est pas un
EstChiffre paramètre est un caractère
chiffre
numérique (chiffre)
- <> 0 sinon
EstMin (caractère) retourne:
Vérifie si le caractère fourni en
- 0 si le caractère n'est pas une
EstMin paramètre est une lettre
lettre minuscule
minuscule
- <> 0 sinon
EstMaj (caractère) retourne:
Vérifie si le caractère fourni en
- 0 si le caractère n'est pas une
EstMaj paramètre est une lettre
lettre majuscule
majuscule
- <> 0 sinon
EstEspace (caractère) retourne:
Vérifie si le caractère fourni en - 0 si le caractère n'est pas un
EstEspace
paramètre est un espace espace
- <> 0 sinon
Convertit un caractère, fourni en VersMaj (caractère) convertit
VersMaj
paramètre, en majuscule caractère en majuscule

3 sur 64
Par: mme Olfa HAMROUNI JEMLI

Convertit un caractère, fourni en VersMin (caractère) convertit


VersMin
paramètre, en minuscule caractère en minuscule

III. APPLICATION
Écrire un algorithme qui:
- lit une chaîne de caractère dont la longueur ne dépasse pas 50 caractères
- calcule et affiche le nombre de caractères alphanumériques, de lettres, de chiffres, de
caractères majuscules, de caractères minuscules et d'espaces.

4 sur 64
Par: mme Olfa HAMROUNI JEMLI

Chapitre 8: TYPE STRUCTURE


Objectif du chapitre: manipuler le type structure
Plan du chapitre:
I. Définition
II. Structures simples
III. Structures composées
IV. Tableaux de structures
V. Application

1. DEFINITION
Une structure ou encore un enregistrement ets classé parmi les types avancés. Il
contient un ou plusieurs champs groupés sous le même nom pour être traités comme
une seule entité. Ces champs sont hétérogènes dans la mesure où leurs types sont
différents.
Les champs d'une structure sont appelés membres et ils peuvent avoir l'un des types
déjà définis y compris les tableaux et les structures.

2. STRUCTURES SIMPLES
1. DEFINITION
On définit le type structure comme suit:
<Nom_Structure>: structure
Membre 1: type

Membre n: type
Fin structure
Exemples:
 Définition de la structure Etudiant:  Définition de la structure Date
Etudiant: structure Date: structure
Nom: chaine (50) Jour: entier
Prenom: chaine (25) Mois: entier
Adresse: chaine (50) Annee: entier
DateNaiss: chaine (10) Fin structure
Fin structure

5 sur 64
Par: mme Olfa HAMROUNI JEMLI

 Définition de la structure produit


Produit: structure
Code: chaine (6)
Designation: chaine (50)
Prix: réel
Fin structure

2. DECLARATION D'UNE VARIABLE DE TYPE STRUCTURE SIMPLE


P: Produit permet de déclarer une varible P de type Produit.
E1, E2: Etudiant  permet de déclarer 2 varables E1 et E2 de type Etudiant.

3. ACCES AUX MEMBRES D'UNE STRUCTURE SIMPLE


Pour faire référence à un membre particulier, on sépare le nom de la variable de type la
structure concernée de celui du membre visé, avec l'opérateur (.).
Exemples:
p.code permet d'accéder au champ code du produit p,
p.prix permet d'accéder au champ prix du produit p,
e1.nom permet d'accéder au champ nom de l'étudiant e1,
e2.adresse permet d'accéder au champ adresse de l'étudiant e2.
Exercice
Ecrire un algorithme permettant de créer une variable p de type la structure produit et de
l'affecter les informations suivantes: (prod1, chaise, 15).
SOLUTION
ALGORITHME Essai
DEBUT
Produit: structure
Code: chaine (6)
Designation: chaine (50)
Prix: réel
Fin structure
P: produit
Copier_Chaine (p.code, "prod1")
Copier_Chaine (p.designation, "chaise")
p.prix  15
FIN
Dans la mémoire centrale, la variable p de structure produit sera représentée comme
suit:

6 sur 64
Par: mme Olfa HAMROUNI JEMLI

La variable P
prod1 Le champ code

Chaise
Le champ Désignation
15

Le champ Prix

3. STRUCTURES COMPOSEES
Revenons à l'exemple de la structure Etudiant et supposons que l'adresse n'est pas une
chaîne de caractères mais elle est une structure qui est définie comme suit:
Adr: structure
Rue: entier
Cite chaine (20)
Gouvernorat: chaine (50)
CodePostal: entier
Pays: chaine (50)
Fin structure
Supposons de même qu'on recourt à la structure Date déjà défini pour définir le champ
DateNaiss. La structure Etudiant serait alors définie comme suit:
Etudiant: structure
Nom: chaine (50)
Prenom: chaine (25)
Adresse: Adr
DateNaiss: Date
Fin structure
Exercice:
Ecrire un algorithme permettant de créer une variable de type Etudiant et de l'affecter les
informations suivantes: (Bensaleh, Karim, (5, rue abdellah ibn raweha, kairouan, 3199,
Tunisie), (12,12,1977))
ALGORITHME Essai2
DEBUT
Adr: structure
Rue: entier
Cite chaine (20)
Gouvernorat: chaine (50)
CodePostal: entier
Pays: chaine (50)

7 sur 64
Par: mme Olfa HAMROUNI JEMLI

Fin structure
Date: strucure
Jour: entier
Mois: entier
Annee: entier
Fin structure
Etudiant: structure
Nom: chaine (50)
Prenom: chaine (25)
Adresse: Adr
DateNaiss: Date
Fin structure
E: Etudiant
Copier_Chaine (e.Nom, "Bensaleh")
Copier_Chaine (e.Prenom, "Karim")
e.adresse.Rue5
Copier_Chaine (e.adresse.Cite, " rue abdellah ibn raweha")
Copier_Chaine (e.adresse.Gouvernorat, " Kairouan")
e.adresse.CodePotal  3199
Copier_Chaine (e.adresse.Pays, " Tunisie")
e.DateNaiss.jour  12
e.DateNaiss.mois  12
e.DateNaisse.annee  1977
Fin
Dans la mémoire centrale, la variable e de structure Etudiant sera représentée comme
suit:

8 sur 64
Par: mme Olfa HAMROUNI JEMLI

La variable e
e.Nom

BenSaleh
e.Prenom
Karim
e.adresse.Rue
5
e.adresse.Cite
Rue abdellah ibn raweha
Kairouan e.adresse.Gouvernorat

3199
e.adresse.CodePostal
Tunisie
e.adresse.Pays

12
e.DateNaiss.jour
12
e.DateNaiss.mois
1977

e.DateNaiss.annee

4. TABLEAUX DE STRUCTURES
La syntaxe de définition d'un tableau de structures est la suivante:
<Nom_Tableau>: tableau [1..<Nombre_Elements>] de <Nom_structure>
Exemple
 Définir un tableau de 5 étudiants en se référant à la structure Etudiant déjà définie.
SOLUTION
ListeEtudiants: tableau [1..5] de Etudiant
La représentation, dans la mémoire centrale, de ce tableau est:
1 2 3 4 5
Nom Nom Nom Nom Nom
Prenom Prenom Prenom Prenom Prenom
Adresse Adresse Adresse Adresse Adresse
Rue Rue Rue Rue Rue
Cite Cite Cite Cite Cite
Gouvernorat Gouvernorat Gouvernorat Gouvernorat Gouvernorat
CodePostal CodePostal CodePostal CodePostal CodePostal
Pays Pays Pays Pays Pays
DateNaiss DateNaiss DateNaiss DateNaiss DateNaiss
Jour Jour Jour Jour Jour
Mois Mois Mois Mois Mois
Annee Annee Annee Annee Annee

9 sur 64
Par: mme Olfa HAMROUNI JEMLI

 Accéder aux différents champs de l'étudiant existant dans la case 2 du tableau


ListeEtudiants

ListeEtudiants[1].Nom  permet d'accéder au nom de l'étudiant n° 1;


ListeEtudiants[1].Prenom  permet d'accéder au prénom de l'étudiant n° 1;
ListeEtudiants[1].Adresse.Rue  permet d'accéder à la rue de l'adresse de l'étudiant n°
1;
ListeEtudiants[1].Adresse.Cite permet d'accéder à la cité de l'adresse de l'étudiant n°
1;
ListeEtudiants[1].Adresse.Gouvernorat  permet d'accéder à la gouvernorat de
l'adresse de l'étudiant n° 1;
ListeEtudiants[1].Adresse.CodePostal  permet d'accéder au code postal de l'adresse
de l'étudiant n° 1;
ListeEtudiants[1].Adresse.Pays  permet d'accéder au pays de l'adresse de l'étudiant
n° 1;
ListeEtudiants[1].DateNaiss.Jour  permet d'accéder au jour de la date de naissance de
l'étudiant n° 1;
ListeEtudiants[1].DateNaiss.Mois  permet d'accéder au mois de la date de naissance
de l'étudiant n° 1;
ListeEtudiants[1].DateNaiss.Annee  permet d'accéder à l'année de la date de
naissance de l'étudiant n° 1.

5. APPLICATION
Soit un tableau de structure produit. Le nombre de produits maximum est 100. Un
produit est défini par sa référence, son libellé, sa couleur, son prix et sa quantité en
stock.
Écrire un algorithme qui permet de:
- demander de l'utilisateur de lire un nombre n<=100
- remplir le tableau avec n produits dont les caractéristiques sont entrées par
l'utilisateur.
- Calculer et afficher la quantité moyenne stockée
- Calculer et afficher la référence du produit qui a le plus grand prix

10 sur 64
Par: mme Olfa HAMROUNI JEMLI

Chapitre 9: LA RECURSIVITE
Objectif du chapitre: Savoir écrire des versions récursives de sous-programmes.
Plan du chapitre:
I. Introduction
II. Exemples
a. Exemple 1: la factorielle d'un entier
b. Exemple 2: le PGCD de deux entiers

1. Introduction
On appelle un sous-programme récursif un sous-programme qui s'appelle, soit lui-même,
soit par l'intermédiaire d'un autre sous-programme. La récursivité est un domaine très
intéressant de l'informatique, un peu abstrait, mais très élégant; elle permet de résoudre
certains problèmes d'une manière très rapide, alors que si on devait les résoudre de
manière itérative, il nous faudrait beaucoup plus de temps et de structures de données
intermédiaires.

La récursivité utilise toujours la pile du programme en cours. On appelle "pile" une zone
mémoire réservée à chaque programme. Son rôle est de stocker les variables locales et
les paramètres d'un sous-programme.
Supposons que nous sommes dans une procédure "proc1" dans laquelle nous avons des
variables locales. Ensuite nous faisons appel à une procédure "proc2"; comme le
microprocesseur va commencer à exécuter "proc2" mais qu'ensuite il reviendra continuer
l'exécution de "proc1", il faut bien stocker quelque part les variables de la procédure en
cours "proc1"; c'est le rôle de la pile. Tout ceci est géré de façon transparente pour
l'utilisateur.

Dans un sous-programme récursif, toutes les variables locales sont stockées dans la pile,
et empilées autant de fois qu'il y a d'appels récursifs. Donc la pile se remplit
progressivement, et si on ne fait pas attention on arrive à un "débordement de pile".
Ensuite, les variables sont désempilées.

Un sous-programme récursif comporte un appel à lui-même, alors qu'un sous-


programme non récursif ne comporte que des appels à d'autres sous-programmes. Tout
sous-programme récursif comporte une instruction (ou un bloc d'instructions) nommée
"point terminal" ou "point d'appui" ou "point d'arrêt", qui indique que le reste des
instructions ne doit plus être exécuté.

La forme générale d'un sous-programme récursif est:

11 sur 64
Par: mme Olfa HAMROUNI JEMLI

Procédure recursive(paramètres);
// Déclaration des variables locales
Début
si (TEST_D'ARRET) alors
Instructions du point d'arrêt
sinon //----- exécution
instructions;
recursive(paramètres changés); // appel récursif
instructions;
fin si
Fin

2. Exemples
a. Exemple 1: la factorielle d'un entier
L'exemple de fonction récursive le plus utilisé est fourni par la fonction mathématique
factorielle qui peut se définir ainsi:
F(0)=1
F(1)=1
F(n)=n * F(n - 1) pour n>1

La 3ème ligne comporte à son tour une référence à la fonction, d'où la récursivité. Cette
récursivité permet d'aboutir à un résultat si on l'applique après un nombre fini de fois.
La version récursive de la fonction F en écriture algorithmique est:
FONCTION F (n: entier):entier
DEBUT
Si ((n=0) ou (n=1)) Alors
Retourner (1)
Sinon
Retourner (n * F (n - 1))
Fin Si
FIN
On suppose écrire l'algorithme principal suivant:
Algorithme Test
var x:entier
Début
x=F(5)
Fin
Essayons de faire une exécution à la main:

12 sur 64
F(4)
Paramètre: n=4 Retourner 6
Retourner: 4*F(3)
Par: mme Olfa HAMROUNI JEMLI
F(3)
Paramètre: n=3 Retourner 2
Retourner Retourner: 3*F(2)
120 F(5)
Et la valeur Paramètre:n=5 Retourner 24
de x dans F(2)
Retourner:5*F(4)
l'algorithme Paramètre: n=2 Retourner 1
est: 120 Retourner: 2*F(1)

F(1)
Paramètre: n=1
Retourner: 1

Exemple 2:le PGCD de deux entiers


Sachant que la fonction qui calcule le PGCD de deux valeurs entières est définie comme
suit:
PGCD(m, 0)=m
PGCD(m, n)= PGCD (n, m%n)

La version algorithmique de la fonction PGCD est:


FONCTION PGCD (m: entier, n: entier):entier
DEBUT
Si (n=0) Alors
Retourner (m)
Sinon
Retourner (PGCD (n, m%n))
Fin Si
FIN

On suppose écrire l'algorithme principal suivant:


Algorithme Test
var x:entier

13 sur 64
Par: mme Olfa HAMROUNI JEMLI

Début
x=PGCD(12,7)
Fin
Essayons de faire une exécution à la main:
Retourner PGCD(12,7)
1
Et la valeur Paramètres: m=12, n=7
de x dans Retourner PGCD(7,5) Retourner 1
l'algorithme
est: 1 PGCD(7,5)
Paramètres: m=7, n=5
Retourner PGCD(5,2) Retourner 1
PGCD(5,2)
Paramètres: m=5, n=2
Retourner PGCD(2,1) Retourner 1
PGCD(2,1)
Paramètres: m=2, n=1
Retourner PGCD(1,0) Retourner 1
PGCD(1,0)
Paramètres: m=1, n=10
Retourner 1

Exemple 3:le produit de deux entiers


Exemple 4:l'exposant
Exemple 5:la longueur d'une chaîne de caractères

14 sur 64
Par: mme Olfa HAMROUNI JEMLI

Chapitre 10: LES FICHIERS

1. Introduction
Le traitement des données exige leur présence en mémoire pendant l'exécution du
programme concerné. Mais, la plupart du temps, il faut également que ces données
soient conservées de manière durable. Comme exemple, on peut citer les données
relatives aux clients d'une entreprise. De telles données (code client, nom client et
adresse client) sont le plus souvent exploitées sur une longue période. Elles doivent
pouvoir être rappelées à tout moment et, en particulier, mises à jour au moment voulu.
Pour atteindre l'objectif escompté, ces données seront écrites dans un fichier qui sera
stocké sur une mémoire de masse et accessible au programme manipulant ces données.

2. Définition
Un fichier est appelé en anglais file. Il s'agit d'un ensemble structuré de données
stockées en général sur un support de masse (disquette, disque dur, disque optique,
etc.). On manipule plusieurs types de fichiers:fichier texte, fichier d'enregistrements, etc.
On distingue généralement deux types d'accès:
- Accès séquentiel
Il consiste à accéder aux informations de manière séquentielle, càd suivant l'ordre où
elles apparaissent dans le fichier. Un fichier à accès séquentiel présente les
caractéristiques suivantes:
 Pas de cellule vide
 On accède à une cellule quelconque en se déplaçant depuis la cellule de départ
 L'ajout d'une cellule se fait à la fin de fichier
- Accès direct
Il consiste à accéder à n'importe quel enregistrement repéré par son numéro d'ordre.
Un fichier à accès direct a les caractéristiques suivantes:
 Cellule vide possible
 On peut directement accéder à une cellule
 On peut modifier voir détruire n'importe quelle cellule

Dans ce qui suit, nous allons manipuler des fichiers de structures.

3. Primitives de base sur les fichiers


3.1. Déclaration d'un fichier

15 sur 64
Par: mme Olfa HAMROUNI JEMLI

La syntaxe de déclaration d'un fichier est:


Nom_Fichier: FICHIER de type
Exemple:
Fich : FICHIER d’étudiant
F : FICHIER de texte

3.2. Ouverture d'un fichier


Avant qu'un programme puisse manipuler un fichier, on doit commencer par l'ouvrir.
L'opération d'ouverture consiste à chercher l'adresse de la première cellule du fichier en
vue d'opérations ultérieures sur le fichier.
L'ouverture d'un fichier se fait grâce à la fonction ouvrir. La syntaxe est :
Ouvrir (Nom_Fichier:chaine, Mode_Acces:chaine)
- ouvrir est une fonction qui retourne une valeur de type FICHIER. La valeur renvoyée
par cette fonction peut être égale à NULL au cas où il n'existe pas un fichier portant le
nom spécifié dans l'entête de ouvrir.
- Nom_Fichier est le chemin complet d'un fichier existant sur un disque
- Mode_Acces est un caractère qui indique la nature des opérations que le programme
devra exécuter après ouverture du fichier. Le tableau suivant résume les possibilités
d'accès à un fichier:
Mode d'accès Signification
"r" Ouvrir le fichier en lecture (Read). Fopen
retourne le pointeur NULL si le fichier
n'existe pas ou introuvable.
"w" Ouvrir le fichier en écriture (Write). Le
fichier est créé s'il n'existe pas encore,. S'il
existe déjà, le contenu est écrasé et
remplacé par le nouveau.
"a" Ouvrir le fichier pour ajout de données
(Append). L'ajout veut dire l'écriture en fin
de fichier. Le fichier est créé s'il n'existe
pas.

Exemple:
Écrire un algorithme qui permet d'ouvrir un fichier séquentiel nommé xyz.dat pour
lecture. Le fichier existe sous c: dans un répertoire nommé Travaux. L'algorithme permet
de tester si le fichier est ouvert ou non.

16 sur 64
Par: mme Olfa HAMROUNI JEMLI

Algorithme Exp1
Début
Fich:FICHIER
Fich=ouvrir ("c:\Travaux\xyz.dat", "r", "séquentiel");
Si (Fich=NULL) écrire ("Fichier non ouvert")
Sinon écrire ("Fichier ouvert")
Fin si
Fin

Notion de nom externe et de nom interne


Les fichiers ne se manipulent pas directement par leur nom, dit souvent, nom externe,
mais par un nom interne choisi librement par le programmeur. Il s'agit d'un
identificateur. L'association entre le nom interne et le nom externe se fait lors de
l'ouverture de fichier. En général, un nom interne est un identificateur manipulé au sein
d'un programme, par contre un nom externe est son correspondant sur le disque.
A la suite de l'exemple précédent, Fich est le nom interne du xyz.dat. En outre, xyz.dat,
qui existe sous le c:\Travaux, est le nom externe de Fich.

3.3. Fermeture d'un fichier


Quand un fichier ne sert plus, on peut le fermer. La fonction assurant la fermeture d'un
fichier est: fermer. La syntaxe est:
fermer (Nom_Fichier)
La fonction fermer possède un paramètre qui est de type FICHIER et elle retourne:
 Vrai si le fichier est fermé
 faux sinon

Exemple:
Algorithme Exp2
Début
Fich:FICHIER
Fich=ouvrir ("c:\Travaux\xyz.dat", "r", "séquentiel")
Si (Fich=NULL) écrire ("Fichier non ouvert")
Sinon
écrire ("Fichier ouvert")
fermer (Fich)
Fin si
Fin

17 sur 64
Par: mme Olfa HAMROUNI JEMLI

La fonction fermerTous permet de fermer tous les fichiers ouverts dans un programme.
Le prototype de la fonction est:
fermerTous()
La fonction retourne une valeur qui présente le nombre de fichiers fermés.

3.4. Indicateur de fin de fichier


Pour vérifier si la fin de fichier est atteinte ou non, il existe la fonction finFichier (en algo)
et feof (en C). Les prototypes de ces fonctions sont:
Écriture algorithmique:
Fonction finFichier(Nom_Fichier): entier
Écriture C:
Int feof(Nom_Fichier);
La fonction retourne:
- une valeur non nulle si la fin de fichier n'est pas atteinte
- Une valeur nulle si la fin de fichier est atteinte

Opérations d'écriture et de lecture


Pour lire ou écrire des données à partir d'un fichier ou dans un fichier, on dispose des
fonctions analogues à celles qui servent à saisir des données à partir du clavier et à les
afficher sur écran. Autre la lecture et l'écriture par caractère, par lignes et avec
formatage, on peut aussi transférer des blocs de données (des enregistrements) depuis
ou vers un fichier.
Les 2 routines qui assurent la lecture et l'écriture par blocs (enregistrements) sont: fwrite
(fEcrire) et fread (fLire).
 Écriture de bloc dans un fichier: fwrite (fEcrire)
La fonction fEcrire (en algorithmique) et fwrite (en C) admettent les prototypes suivants:
Écriture algorithmique:
Fonction fEcrire (Buffer, Taille, Nombre_Blocs, Nom_Fichier): entier
Écriture C:
Int fwrite (Buffer, Taille, Nombre_Blocs, Nom_Fichier);
Avec:
- Buffer contient l'adresse d'un bloc de données de type structure (Client, Article,
Personne, etc.)
- Taille est la dimension d'un objet (exprimée par l'opérateur sizeof)
- Nombre_Blocs est le nombre d'objets à écrire dans le fichier
- La fonction renvoie le nombre de blocs écrits
Exemple: Soit le fichier xyz.dat déjà vu dans l'exemple précédent, écrire une fonction
nommée Remplir qui remplit le fichier xyz.dat par 5 étudiants dont les informations sont

18 sur 64
Par: mme Olfa HAMROUNI JEMLI

lues à partir du clavier. Sachant qu'un étudiant est défini par: un numéro de carte et un
téléphone.
Solution:
Etudiant=enreg
int nce;
int tel;
Fin enreg

Fonction Remplir(): Fichier


Début
F:FICHIER
Etud: Etudiant
i:entier
f=ouvrir ("D:/TEST_C/xyz.dat","a")
Si (f=NULL) Alors
écrire ("Fichier non ouvert")
Sinon
Pour i de 1 à 5 faire
Écrire ("Donner le nce du i ème étudiant:")
Lire (Etud.nce)
Écrire ("\nDonner le tel du i eme étudiant:")
Lire (Etud.tel)
fEcrire(Etud, sizeof(Etud),1,f)
Fin pour
Fin si
Fermer(f)
Retourner (f)
Fin

#include <stdio.h>
typedef struct
{
int nce;
int tel;
}Etudiant;
FILE* Remplir()
{
FILE* f;

19 sur 64
Par: mme Olfa HAMROUNI JEMLI

Etudiant Etud;
int i;
f=fopen("D:/TEST_C/xyz.dat","a");
if (f==NULL)
{
printf("Fichier non ouvert");
}
else
{
for(i=1;i<=2;i++)
{
printf("Donner le nce du %d eme etudiant:",i);
scanf("%d",&Etud.nce);
printf("\nDonner le tel du %d eme etudiant:",i);
scanf("%d",&Etud.tel);
fwrite(&Etud, sizeof(Etud),1,f);
}
}
fclose(f);
return (f);
}
void main()
{
FILE * Fich;
Fich=Remplir();
}

 Lecture de bloc à partir d'un fichier: fread (fLire)


La fonction fLire (en algorithmique) et fread (en C) admettent les prototypes suivants:
Écriture algorithmique:
Fonction fLire (Buffer, Taille, Nombre_Blocs, Nom_Fichier): entier
Écriture C:
Int fread (Buffer, Taille, Nombre_Blocs, Nom_Fichier);

Exemple: Soit le fichier xyz.dat déjà vu dans l'exemple précédent et rempli par 5
étudiant, écrire une fonction nommée Affichage qui affiche le contenu du fichier xyz.dat.
Solution:
Fonction Affichage(f:FICHIER)

20 sur 64
Par: mme Olfa HAMROUNI JEMLI

Début
i:entier
E:Etudiant

f=ouvrir("D:/TEST_C/xyz.dat","r")
Si (f=NULL)
écrire ("Fichier non ouvert")
Sinon
Tant que (non finFichier(f)) faire
fLire(E,sizeof(E),1,f)
écrire("ETUDIANT", i)
écrire("NCE:",E.nce)
printf("TEL:", E.tel)
Fin tant que
Fin si
Fermer(f)
Fin

void Affichage(FILE* f)
{
int i;
Etudiant E;
f=fopen("D:/TEST_C/xyz.dat","r");
if (f==NULL)
{
printf("Fichier non ouvert");
}
else
{
While(!feof(f))
{
fread(&E,sizeof(E),1,f);
printf("ETUDIANT %d\n",i);
printf("NCE:%d\n",E.nce);
printf("TEL:%d\n", E.tel);
}
}
fclose(f);

21 sur 64
Par: mme Olfa HAMROUNI JEMLI

4. Manipulation des fichiers à accès direct


Jusqu'à maintenant, nous avons supposé que le parcours d'un fichier se fait d'une
manière séquentielle. L'accès à un bloc n nécessite le parcours des n-1 blocs précédents.
Cependant, l'accès direct permet de positionner le pointeur de positionnement du fichier
sur un élément n sans recourir à parcourir séquentiellement les n - 1 qui le précède.
L'accès au n ième élément se fait directement. Il existe des fonctions qui ne s'appliquent
que si l'accès est direct.

a. Positionnement dans un fichier: fseek (fRecherche)


Le prototype de la fonction est:
Écriture algorithmique:
Fonction fRechercher (Nom_Fichier, Offset, Base)
Écriture C:
Int fseek (Nom_Fichier, Offset, Base);
Avec:
- Le paramètre Offset donne ici le nombre d'octets dont il faut décaler le pointeur de
position relativement à Base. Si Offset est positif, le déplacement aura lieu en
direction de la fin de fichier. Si Offset est négatif, le déplacement s'effectue vers le
début du fichier.
- Le paramètre Base précise l'origine de déplacement dans le fichier. Les valeurs
possibles de ce paramètre sont:
0: début de fichier
1: Position actuelle dans le fichier
2: Fin de fichier
Exemple:
Soit le fichier xyz.dat déjà vu dans l'exemple précédent, contenant des enregistrements
sur des étudiants, écrire un algorithme et un programme C qui permettent d'afficher
l'enregistrement numéro 3, ensuite l'enregistrement numéro 1.
Solution:
Etudiant=enreg
Nce:entier
Tel:entier
Fin enreg
Algorithme test
Début
F:FICHIER E:Etudiant
F=ouvrir("D:/TEST_C/xyz.dat", "r");

22 sur 64
Par: mme Olfa HAMROUNI JEMLI

si (F=NULL)
écrire ("Fichier non ouvert")
sinon
fRechercher (F, 2 * sizeof(Etudiant), 0);
fLire( &E, sizeof(Etudiant), 1, F);
écrire ("Le bloc numéro 3 est l'étudiant dont le nce est E.nce et le tel est: E.tel")
fseek (F, 0,0);
fLire( &E, sizeof(Etudiant), 1, F);
écrire ("Le bloc numéro 1 est l'étudiant dont le nce est E.nce et le tel est: E.tel")
fin si
fermer(F)
Fin

#include <stdio.h>
typedef struct
{
int nce;
int tel;
}Etudiant;
void main()
{
FILE * F; Etudiant E;
F=fopen("D:/TEST_C/xyz.dat", "r");
if (F==NULL)
{ printf("Fichier non ouvert"); }
else
{
fseek (F, 2 * sizeof(Etudiant), 0);
fread( &E, sizeof(Etudiant), 1, F);
printf("Le bloc numéro 3 est l'etudiant dont le nce est %d et le tel est: %d\n\n",
E.nce,E.tel);
fseek (F, 0,0);
fread( &E, sizeof(Etudiant), 1, F);
printf("Le bloc numéro 1 est l'etudiant dont le nce est %d et le tel est: %d",
E.nce,E.tel);
}
Fclose(f);
}

23 sur 64
Par: mme Olfa HAMROUNI JEMLI

b. Passage vers le début du fichier: rewind


Le prototype de la fonction qui permet de passer le pointeur de positionnement dans un
fichier est:
Écriture algorithmique:
Fonction fDebut(Nom_Fichier)
Écriture C:
Void rewind (Nom_Fichier);

Exemple:
fDebut(F)
rewind (F);
Remarque: l'expression rewind (F) est équivalente à: fseek(F, 0, 0);

24 sur 64
Par: mme Olfa HAMROUNI JEMLI

Chapitre 8: LES POINTEURS

1. Définition
Un pointeur est une donnée constante ou variable qui mémorise l'adresse d'une variable.
On dit que le pointeur fait référence à la variable. Il s'agit d'un type de donnée dont les
valeurs sont les adresses des objets de différents types de donnée. Ces valeurs sont
l'ensemble des adresses de la mémoire centrale auquel on ajoute une adresse nulle.

2. Déclaration de pointeurs
La syntaxe générale de déclaration d'un pointeur en langage C est:
<Type> * <Nom_Pointeur>;
Exemple:
int * ptre;
 ptre est un pointeur sur un entier. La variable ptre contiendra l'adresse ou la
référence d'une variable de type entier.
char * ch;
 ch est une chaîne de caractères. La variable ch contiendra l'adresse ou la
référence du premier caractère d'une variable de type chaîne de caractères.

3. Gestion de pointeurs
3.1. Initialisation d'un pointeur
Si on suppose les déclarations suivantes et on se base sur les déclarations précédentes:
int x;
char chaine[]="Hello";
ptre=&x;
ch=&chaine;
On déduit que ptre pointe vers la variable x. En outre, on déduit que ch fait référence à
la variable chaine.

La représentation de ces variables dans la mémoire centrale ressemble à la suivante:

25 sur 64
Par: mme Olfa HAMROUNI JEMLI

26 sur 64
Par: mme Olfa HAMROUNI JEMLI

Programmes système

Programmes système

Chaine contient la chaîne Hello. La


lettre H se trouve à l'adresse 408
X se trouve à l'adresse 400
H E L L O \0
Ptre
400 408 ch

D'après ce qui a été représenté, on dit que:


 ptre et ch sont des variables pointeurs
 x et chaine sont des variables pointées.

3.2. Modification du contenu d'une variable pointée


La syntaxe permettant d'accéder au contenu d'une variable pointée est:
*<Nom_Pointeur>.
La syntaxe permettant de modifier le contenu d'une variable pointée est:
* <Nom_Pointeur>=<valeur> | <Expression>;
Exemple:
Affecter à la variable pointée ptre la valeur 10.
 *ptre = 10;
cet écriture est équivalente à: x=10;

3.3. Arithmétique des pointeurs


Le langage C admet les opérateurs: +, - , ++, -- , == et != pour les pointeurs.
 Addition
#include <stdio.h>
main()
{
char * ch="Bonjour";
printf ("%c", *ch);// Affichage du caractère B
ch=ch+2;
printf ("%c", *ch);//Affichage du caractère n
}
 Soustraction

27 sur 64
Par: mme Olfa HAMROUNI JEMLI

#include <stdio.h>
main()
{
char * ch="Bonjour";
ch=ch+5;
printf ("%c", *ch);//Affichage du caractère u
ch=ch-2;
printf ("%c", *ch);//Affichage du caractère j
}
 Incrémentation
#include <stdio.h>
main()
{
char * ch="Bonjour";
printf ("%c", *ch);//Affichage du caractère B
ch=ch++;
printf ("%c", *ch);//Affichage du caractère o
}
 Décrémentation
#include <stdio.h>
main()
{
char * ch="Bonjour";
printf ("%c", *ch);//Affichage du caractère B
ch=ch+3;
printf ("%c", *ch);//Affichage du caractère j
ch=ch--;
printf ("%c", *ch);//Affichage du caractère n
}
 Comparaison
La comparaison de 2 pointeurs ne renseigne l'égalité que si les deux pointeurs pointent
vers la même variable.
Exemple:
int x=10 ; int y = 10; int z = 20;
int * px = &x; int * py=&y; int * pz=&z;
px != py
px != pz
py != pz

28 sur 64
Par: mme Olfa HAMROUNI JEMLI

4. Pointeurs et chaînes de caractères


Une chaîne de caractères est une suite de caractères qui se termine par le caractère \0.
Elle est aussi un pointeur sur le premier élément de cette suite soit le premier caractère.
La déclaration d'une chaîne de caractères suit la syntaxe suivante: Char *
<Nom_Chaine>;
Exemple:
Char * chaine1; => chaine1 reçoit l'adresse du premier caractère de la chaîne pointée
par chaine1.
Char * chaine2="Hello"; => chaine2 reçoit l'adresse du premier caractère de la chaîne
Hello, soit l'adresse de H.
L'écriture Char * chaine2="Hello"; est équivalente à l'écriture: char chaine2[]="Hello";

5. Gestion dynamique
La déclaration d'un pointeur devrait être suivie d'une réservation d'espace mémoire. Au
cours des chapitres précédents, les déclarations des variables étaient d'une manière
statique. Ceci peut causer une saturation de la mémoire centrale et un plantage des
programmes qui manipulent beaucoup de variables. En effet, avec cette réservation
statique, le programmeur ne peut pas gérer l'espace mémoire (allouer et libérer de
l'espace mémoire au cas de besoin) d'où la nécessité d'une gestion dynamique.
Voici un exemple montrant le besoin d'une allocation et mettant en relief les avantages
des pointeurs par rapport aux tableaux.
A la rentrée universitaire de l’année 2003/2004, on dispose de 4000 étudiants. Dans le
service scolarité, les étudiants sont enregistrés dans un tableau pour être gérés plus
tard. Durant le semestre, les problèmes suivants sont rencontrés :
- 3 nouveaux étudiants se sont orientés vers notre institution. Que faire et notre tableau
est plein et ne contient plus d’espace libre?
- 10 étudiants sont partis pour une autre institution donc ils ne devront plus figurer dans
le tableau => ils devront être supprimés du tableau et ceci va causer des trous qui ne
peuvent plus être exploités.
Avec ces deux cas de figure, il est clair que la gestion statique cause des problèmes
pourrant être remédiés par la gestion dynamique. Cette dernière assure l’allocation
d’espace mémoire et la libération d’espace mémoire au cas de besoin.
En langage C, les fonctions qui permettent d’allouer dynamiquement de l’espace mémoire
sont :
- malloc ( Memory ALLOCation)
- calloc (Contiguous ALLOCation)
- realloc (REALLOCation)

29 sur 64
Par: mme Olfa HAMROUNI JEMLI

et de libérer de l’espace mémoire est free.


Ces fonctions s’intègrent dans la bibliothèque stdlib.h
Les fonctions d’allocation d’espace mémoire ne sont pas typées dans la mesure ou elles
fournissent une adresse sous la forme d’un pointeur générique c'est à dire de type void*.
Ce dernier peut être converti suivant les besoins.
Pour décider de la taille à allouer, le programmeur devra lui-même préciser la taille en
octet de l’emplacement voulu. De ce fait, il devrait se baser sur l’opérateur sizeof.

a. Fonction malloc
La fonction malloc alloue dynamiquement un emplacement formé d’un nombre d’octets
consécutifs. Pour cela, on transmet comme paramètre de fonction, un nombre entier
exprimant la dimension du bloc mémoire que l’on désire réserver. La fonction malloc
retourne au programme un pointeur vers l’adresse du début de ce bloc si l’opération est
réussie et le pointeur NULL sinon.
Le résultat fourni par malloc est un pointeur générique qui peut être converti en un
pointeur de type quelconque.
La syntaxe de la fonction malloc est :
Void * malloc (taille en octets) ;
Exemple 1 :
Allouer dynamiquement de l’espace mémoire pour 20 entiers
Ptre= malloc (20 * sizeof (int)) ;
Ptre est l’adresse du bloc mémoire alloué pour les 20 entiers en cas de réussite
d’opération.
Ptre est la valeur NULL en cas d’échec d’opération s’il y a insuffisance d’espace mémoire.
Exemple 2
Ecrire un programme qui déclare une suite de 7 entiers et l’initialise par des 0
#include <stdlib.h>
main()
{
int * ptre ; int i;
ptre=malloc(7 * sizeof (int));
for (i=1;i<=7;i++)
{
*ptre=0;
ptre++;
}
}
Le bloc mémoire alloué par ce programme peut être représenté comme suit :

30 sur 64
Par: mme Olfa HAMROUNI JEMLI

ptre

0 0 0 0 0 0

0
b. Fonction calloc
Elle réserve un bloc mémoire dont la taille est réservée d’avance et retourne au
programme, en cas de succès de l’opération, l’adresse du début de ce bloc et le pointeur
NULL en cas d’échec. A la différence de malloc, calloc admet deux paramètres. La
syntaxe générale est :
Void * calloc (nombre, taille en octets) ;
Les deux fonctions malloc et calloc se différencient non seulement par le nombre de
paramètres mais également par le contenu du bloc réservé.
Avec une allocation faite par malloc, tous les octets du bloc alloué contiennent des
valeurs aléatoires. En revanche, calloc initialise chaque octet du bloc par la valeur 0.

Exemple 1 0
#include <stdlib.h> 0
#include <stdio.h> 0
0
main()
0
{ 0
int * ptre ; int i; 0
ptre=calloc(7 , sizeof (int));
for (i=1;i<=7;i++)
{ printf (“%d\n”, *ptre); ptre++ ; }
}

b. Fonction free
Elle assure la libération d’espace mémoire dont l’adresse de début est fournie en
paramètre. La syntaxe générale est :
void free (void * adr) ;
Exemple 1
#include <stdlib.h>
#include <stdio.h>
main()
{ int * ptre ; int i; int * p;
ptre=calloc(7 * sizeof (int));

31 sur 64
Par: mme Olfa HAMROUNI JEMLI

p=ptre;
for (i=1;i<=7;i++)
{ printf (“%d\n”, *ptre); ptre++ ; }
free (p) ;
}

c. Fonction realloc
Par sa nature, la fonction free libère toujours un emplacement dans sa totalité. La
fonction realloc peut pallier ce défaut. Elle permet de libérer une partie d’une zone
préalablement allouée. En outre, elle permet d’accroître un emplacement donné tout en
conservant son contenu.
La syntaxe générale est :
Void * realloc (void * adr, taille en octets) ;
Deux cas seront rencontrés : le cas de réduction de la taille et le cas d’augmentation de
la taille d’un emplacement.

- cas de réduction de la taille d’un emplacement


Si on alloue initialement un emplacement pour 100 entiers par :
Adr = malloc(100 * sizeof (int)) ;
Il est possible de réduire cet emplacement par l’instruction suivante :
Adr= realloc (adr, 60 * sizeof (int)) ;
 Les octets réservés aux 40 entiers vont être libérés à partir de la fin de la zone
initialement réservée.
- cas de réduction de la taille d’un emplacement
Si on alloue initialement un emplacement pour 100 entiers par :
Adr = malloc (100 * sizeof (int)) ;
Il est possible d’augmenter cet emplacement par l’instruction suivante :
Adr= realloc (adr, 120 * sizeof (int)) ;
 Les octets réservés aux 20 entiers vont être ajoutés à la fin de la zone initialement
réservée.
Application
Ecrire un programme permettant de lire une chaîne de caractères ch et de la copier dans
une autre chaîne ch1 sans utiliser la fonction strcpy de la bibliothèque string.h.

6. pointeurs et structures
Supposons déclarée une structure telle que :
Struct article
{

32 sur 64
Par: mme Olfa HAMROUNI JEMLI

char Code [5];


char Libelle [20] ;
float Prix ;
};
Alors struct article * Pa ;, définit un pointeur Pa vers des données de type struct article.
Après la définition struct article art ;, on peut via Pa=&art, ranger l’adresse de la variable
structurée art dans le pointeur Pa.
On dit alors que la variable Pa est une variable pointeur et la variable art est une variable
pointée par Pa.

a. Accès aux champs d’une structure pointée


Plus généralement, si pointeur contient l’adresse d’une variable structurée alors :
(*pointeur).champ représente la syntaxe permettant d’accéder à un champ de structure
via un pointeur. Les parenthèses autour de l’expression *pointeur sont indispensables.
L’écriture peut être remplacée par l’expression suivante :
Pointeur  champ
Pour l’expression de la structure article, les expressions :
(*Pa).code, (*Pa).libelle et (*Pa).prix
Sont équivalentes à :
Pa code, Pa  libelle et Pa  prix
Exemple 1
En se basant sur les déclarations suivantes :
Struct article
{
char Code [5];
char Libelle [20] ;
float Prix ;
};
struct article * Pa ;
Ecrire un programme qui crée un article dont le code est P1, le libellé est Chaise et le prix
est 15.25 et qui est pointé par la variable pointeur Pa
Solution
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
main ()
{
Struct article

33 sur 64
Par: mme Olfa HAMROUNI JEMLI

{
char Code [5];
char Libelle [20] ;
float Prix ;
};
struct article * Pa ;
Pa = malloc (sizeof (struct article));
Strcpy (Pa code, "P1");
Strcpy (Pa  libelle, "Chaise");
Pa  prix = 15.25;
}
Exemple 2
En se basant sur les mêmes déclarations, afficher le contenu de la variable pointée par
Pa.
Solution
#include <stdlib.h>
#include <stdio.h>
main()
{
Struct article
{
char Code [5];
char Libelle [20] ;
float Prix ;
};
struct article * Pa ;
Pa = malloc (sizeof (struct article));
Strcpy (Pa code, "P1");
Strcpy (Pa  libelle, "Chaise");
Pa  prix = 15.25;
Printf ("Le code est:%s, le libellé est:%s et le prix est:%f", Pa code, Pa  libelle, Pa 
prix);
}

b. Application
Etant donné qu'une personne est définie par un NCIN, un nom, un prénom, un âge et
une adresse, écrire un programme qui permet de définir une suite de 20 personnes, de la

34 sur 64
Par: mme Olfa HAMROUNI JEMLI

remplir par des données entrées à partir du clavier et enfin de chercher le nombre de
personnes qui portent le prénom Mohamed.
Solution
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
struct Personne
{
char NCIN[8];
char Nom[20];
char Prenom[15];
int Age;
char Adresse[30];
};
struct Personne * SuitePers;
struct Personne * P;
int i; int cpt;
SuitePers=malloc(2*sizeof(struct Personne));
P=SuitePers;
for (i=1;i<=2;i++)
{ printf ("Donner le NCIN:");
gets(P->NCIN);
printf("Donner le nom:");
gets(P->Nom);
printf("Donner le prénom:");
gets(P->Prenom);
printf("Donner l'age:");
scanf("%d",&P->Age);
printf("Donner l'adresse:");
gets(P->Adresse);
P++;
}
P=SuitePers;
cpt=0;
for (i=1; i<=2;i++)
{

35 sur 64
Par: mme Olfa HAMROUNI JEMLI

if (!strcmp(P->Prenom,"Mohamed")) cpt++;
P++;
}
printf("Le nombre de personne de prenom Mohamed est:%d",cpt);
}

7. Tableaux de pointeurs
On définit les tableaux statiques de pointeurs comme les autres tableaux statiques. Lors
de leur définition, on indique le type des éléments du tableau, le nom du tableau et le
nombre des éléments.
Exemples
 int * TabE[20]
Définit un tableau nommé TabE de 20 pointeurs, chacun d'entre eux pointe vers une
donnée de type int.
Supposons définir une variable int x=10;
Alors l'instruction TabE[0]=&x range l'adresse de x dans le premier élément du tableau
de pointeurs TabE.

 char * TabChaine[20];
Définit un tableau de 20 pointeurs vers des chaînes de caractères.

 struct article * TabArticle[20];


Définit un tableau nommé TabArticle de 20 pointeurs vers des articles. Chaque case
contient l'adresse vers une donnée de type struct article.

Application
Soit un tableau de 10 pointeurs vers des articles (utiliser la structure article déjà vu)
- Ecrire un programme en C qui remplit le tableau par des données entrées à partir
du clavier
- Ecrire un programme en C qui trie le tableau selon le tri par sélection (le critère
est le code et l'ordre est croissant)
Ecrire un programme en C qui permet d'afficher le tableau

36 sur 64
Par: mme Olfa HAMROUNI JEMLI

Chapitre 12: LES LISTES

1. Définition
Une liste est un ensemble d'objets de même type constituant les éléments de la liste. Les
éléments sont chaînés entre eux de sorte qu'on puisse ajouter ou extraire ou éliminer
un ou plusieurs éléments(s). Une liste simple est une structure de données telle que
chaque élément contient:
- des informations caractéristiques de l'application (les caractéristiques d'une
personne ou d'un article par exemple)
- Un pointeur vers un autre élément ou une marque de fin de liste s'il n'y a pas
d'élément successeur.
En mathématiques, une liste correspond à une suite et elle vérifie les propriétés
suivantes:
- elle a un unique premier élément appelé: tête de liste
- elle a un unique dernier élément appelé: queue de liste
- chaque élément possède un unique successeur sauf le dernier
- chaque élément possède un unique prédécesseur sauf le premier

2. Module de gestion de liste


Définition
Un élément d'une liste contient toujours un pointeur sur l'élément suivant ou une marque
indiquant qu'il n'y a pas de suivant (marque NULL en C). Un élément d'une liste est donc
une structure contenant:
- une données spécifique à l'application (exemples: un entier, un réel, une structure
article, une chaîne, etc.)
- un pointeur sur l'élément suivant de la liste
La définition d'une liste se base sur 3 axes:
- un pointeur sur le premier élément de la liste appelé tête ou premier
- un pointeur sur le dernier élément de la liste appelé queue ou dernier
- un pointeur courant nommé courant assurant le parcours de la liste et laissant les
pointeurs Tete et Queue intacts.
Le module de gestion de liste contiendra alors la déclaration d'une liste d'éléments et
l'ensemble des opérations qui s'appliquent sur une liste.

37 sur 64
Par: mme Olfa HAMROUNI JEMLI

Les opérations applicables sur une liste


a. Ajout d'un élément à une liste
L'ajout d'un élément peut se faire soit en tête de liste, soit en fin de liste, soit après
l'élément courant, soit avant l'élément courant.
Pour préparer la spécification et l'implémentation du module de gestion de liste en
langage C, on va attribuer à chaque opération un nom de fonction.
- Pour l'ajout en tête de liste, on lui attribue la fonction AjoutEnTete.
- Pour l'ajout en fin de liste, on lui attribue la fonction AjoutEnFin
- Pour l'ajout après l'élément courant, on lui attribue la fonction AjoutApresCourant
- Pour l'ajout avant l'élément courant, on lui attribue la fonction AjoutAvantCourant

b. Consultation de l'élément courant


Il s'agit de consulter les informations qui concernent l'élément courant de la liste. En
général, la consultation veut dire l'affichage. A cette opération, on correspond la fonction
ConsulterCourant.

c. Mise à jour de l'élément courant


Il s'agit de mettre à jour (modifier) les informations de l'élément courant de la liste. A
cette opération, on correspond la fonction MAJCourant.

d. Suppression de l'élément courant


Il s'agit de supprimer l'élément courant de la liste. Il y a cas de figure:
- Si la liste est vide alors la suppression est impossible
- Si l'élément à supprimer est la tête de la liste alors la nouvelle tête devient
l'élément qui suit l'ancienne tête.
- Si l'élément à supprimer est la fin de la liste alors le nouveau dernier élément
devient l'élément qui précède l'ancien dernier élément.
- Si l'élément à supprimer se trouve au milieu de la liste alors il faut rectifier le
chaînage.
A cette opération, on correspond la fonction SupprimerCourant.

e. Recherche d'un élément dans une liste


La recherche se base sur une donnée fournie par l'utilisateur. Cette donnée est appelée
une clé. Si l'élément satisfaisant la clé existe dans la liste alors il devient l'élément
courant, sinon un message d'erreur s'affiche. On correspond à cette opération la fonction
Recherche.

38 sur 64
Par: mme Olfa HAMROUNI JEMLI

f. Autres opérations
- L'opération de création de liste: la fonction CreerListe.
- L'opération de renvoie de la taille d'une liste (le nombre d'éléments dans la liste): la
fonction TailleListe
- L'opération de passer l'élément courant vers l'élément qui le suit: la fonction Suivant
- L'opération de passer l'élément courant vers l'élément qui le précède: la fonction
Précédent
- L'opération de positionnement sur le premier élément de la liste: la fonction
OuvrirListe
- L'opération de vérification si on est en tête de liste: la fonction DebutListe
- L'opération de vérification si on est en fin de liste: la fonction FinListe
- L'opération de vérification si la liste est vide: la fonction EstVide
- L'opération de destruction de la liste: il consiste à supprimer tous ses éléments: la
fonction DetruireListe
- L'opération d'affichage des informations de tous les éléments de la liste: la fonction
AfficherListe

Spécification du module de gestion de liste


Le module de gestion de liste est composé de:
- un fichier en-tête nommé Liste.h décrivant l'interface du module
- un corps du module nommé Liste.c
Le fichier en-tête est le fichier qui va définir le type Element et qui va donner les
spécifications des fonctions du module de gestion de liste.
On suppose dans ce qui suit qu'on travaille avec une liste d'entiers. De ce fait, la
déclaration dynamique d'une liste se fait comme suit:

typedef struct element * PElement;


typedef struct element
{
int e;
PElement suivant;
} Element;
typedef struct Liste
{
PElement tete;
PElement queue;
PElement courant;
} Tliste;

39 sur 64
Par: mme Olfa HAMROUNI JEMLI

---- Exemple de schématisation d'une liste:


Tete Courant Queue

12 9 -1 0 NULL

Le fichier en-tête Liste.h ressemble au suivant:


typedef struct element * PElement;
typedef struct element
{
int e;
PElement suivant;
} Element;
typedef struct Liste
{
PElement tete;
PElement queue;
PElement courant;
} Tliste;
void CreerListe(Tliste * L);
void OuvrirListe(Tliste * L);
int EstVide (Tliste L);
void AjoutEnTete(Tliste * L, int x);
void AjoutEnFin (Tliste * L, int x);
void AfficherListe(Tliste * L);
int ConsulterCourant (Tliste L);
void MAJCourant (Tliste * L,int x);
void Suivant (Tliste * L);
void Precedent (Tliste * L);
int TailleListe(Tliste* L);
int DebutListe(Tliste L);
int FinListe(Tliste L);
void AjoutAvantCourant(Tliste * L, int x);
void AjoutApresCourant(Tliste * L, int x);
void SupprimerCourant(Tliste * L);
int Recherche(Tliste * L, int x);

40 sur 64
Par: mme Olfa HAMROUNI JEMLI

void DetruireListe(Tliste * L);

Implémentation du module de gestion de liste


Le fichier Liste.c contenant l'implémentation du fichier Liste.h est le suivant:
#include <stdio.h>
#include <stdlib.h>
#include "liste.h"
/****************************************************************/
void CreerListe(Tliste * L)
{
L=malloc(sizeof(TListe));
L->courant=NULL;
L->tete=NULL;
L->queue=NULL;
}
/****************************************************************/
void OuvrirListe(Tliste * L)
{
L->courant=L->tete;
}
/****************************************************************/
int EstVide (Tliste L)
{
if (L.tete==NULL) return(1);
else return (0);
}
/****************************************************************/
void AjoutEnTete(Tliste * L, int x)
{
PElement ptr;
ptr=malloc(sizeof(Element));
ptr->e=x;
ptr->suivant=L->tete;
L->tete=ptr;
L->courant=ptr;
if (L->queue==NULL) L->queue=ptr;
}
/****************************************************************/

41 sur 64
Par: mme Olfa HAMROUNI JEMLI

void AfficherListe(Tliste * L)
{
if (EstVide(*L)) printf ("Liste Est Vide");
else
{
OuvrirListe(L);
while(L->courant != NULL)
{
printf("\n%d",L->courant->e);
L->courant=L->courant->suivant;
}
}
OuvrirListe(L);
}
/****************************************************************/
void AjoutEnFin (Tliste * L, int x)
{
PElement ptr;
ptr=malloc(sizeof(Element));
ptr->e=x;
if (L->tete==NULL)
L->tete=ptr;
else
L->queue->suivant=ptr;
ptr->suivant=NULL;
L->queue=ptr;
L->courant=ptr;
}
/*****************************************************************/
int ConsulterCourant(Tliste L)
{
if (EstVide(L)) printf ("Liste EstVide");
else return (L.courant->e);
}
/*****************************************************************/
void MAJCourant(Tliste * L,int x)
{
if (EstVide(*L)) printf ("Liste EstVide");

42 sur 64
Par: mme Olfa HAMROUNI JEMLI

else
L->courant->e=x;
}
/*****************************************************************/
int DebutListe(Tliste L)
{
if (EstVide(L)) printf ("Liste EstVide");
else if (L.courant==L.tete) return (1);
else return (0);
}
/*****************************************************************/
int FinListe(Tliste L)
{
if (EstVide(L)) printf ("Liste EstVide");
else if (L.courant==L.queue) return (1);
else return (0);
}
/*****************************************************************/
void suivant (Tliste * L)
{
if (EstVide(*L)) printf ("Liste EstVide");
else
if (FinListe(*L)) L->courant = L->tete;
else
L->courant=L->courant->suivant;
}
/*****************************************************************/
void precedent(Tliste * L)
{
PElement ptr;
if (EstVide(*L)) printf ("Liste EstVide");
else
if (DebutListe(*L)) L->courant = L->queue;
else
{
ptr=L->tete;
while (ptr->suivant!=L->courant)
ptr=ptr->suivant;

43 sur 64
Par: mme Olfa HAMROUNI JEMLI

L->courant=ptr;
}
}
/*****************************************************************/
int TailleListe(Tliste * L)
{
int cpt=0;
OuvrirListe(L);
while (L->courant!=NULL)
{
cpt=cpt++;
L->courant=L->courant->suivant;
}
OuvrirListe(L);
return(cpt);
}
/*****************************************************************/
int Recherche(Tliste * L, int x)
{
OuvrirListe(L);
while (L->courant != NULL)
{if (L->courant->e==x) return (1);
else
L->courant=L->courant->suivant;
}
return(0);
}
/*****************************************************************/
void SupprimerCourant(Tliste * L)
{
PElement p;
if (EstVide(*L)) puts("Impression impossible car liste vide");
else
if ((L->courant==L->tete)&&(L->courant==L->queue))
{
free(L->queue);
L->tete=NULL;
L->queue=NULL;

44 sur 64
Par: mme Olfa HAMROUNI JEMLI

L->courant=NULL;
}
else
if (L->courant==L->tete)
{
L->courant=L->courant->suivant;
free(L->tete);
L->tete=L->courant;
}
else
{
p=L->tete;
while (p->suivant!=L->courant)
p=p->suivant;
p->suivant=L->courant->suivant;
free(L->courant);
if (L->courant==L->queue)
{
L->queue=p;
L->courant=p;
}
else
L->courant=p->suivant;
}
}
/*****************************************************************/
void DetruireListe(Tliste * L)
{
PElement p;
OuvrirListe(L);
while (L->courant->suivant!=NULL)
{
p=L->courant->suivant;
SupprimerCourant(L);
L->courant=p;
}
SupprimerCourant(L);
}

45 sur 64
Par: mme Olfa HAMROUNI JEMLI

/*****************************************************************/
void AjoutApresCourant(Tliste * L, int x)
{
PElement p,ptr;
ptr=malloc(sizeof(PElement));
ptr->e=x;
if (EstVide(*L))
{
L->courant=ptr;
L->queue=ptr;
L->tete=ptr;
L->courant->suivant=NULL;
}
else
if (L->courant==L->queue)
AjoutEnFin(L, x);
else
{
p=L->courant->suivant;
L->courant->suivant=ptr;
ptr->suivant=p;
L->courant=ptr;
}
}
/*****************************************************************/
void AjoutAvantCourant(Tliste * L, int x)
{
PElement p,ptr;
ptr=malloc(sizeof(PElement));
ptr->e=x;
if (EstVide(*L))
{
L->courant=ptr;
L->queue=ptr;
L->tete=ptr;
L->courant->suivant=NULL;
}
else

46 sur 64
Par: mme Olfa HAMROUNI JEMLI

if (L->courant==L->tete)
AjoutEnTete(L,x);
else
{
p=L->tete;
while (p->suivant!=L->courant)
p=p->suivant;
p->suivant=ptr;
ptr->suivant=L->courant;
L->courant=ptr;
}
}

Remarque: il y a plusieurs types de listes dont on cite:


- Liste simple avec chaînage simple exprimé par le pointeur suivant qui indique
l'élément qui suit un élément de la liste. Au niveau de ce type de liste, le suivant
de la queue est le pointeur NULL.
- Liste simple avec chaînage double exprimé par le pointeur suivant qui indique
l'élément qui suit un élément de la liste et le pointeur precedent qui indique
l'élément qui précède un élément de la liste. Au niveau de ce type de liste, le
suivant de la queue est le pointeur NULL et le précédent de la tête est le pointeur
NULL.
- Liste circulaire avec chaînage simple exprimé par le pointeur suivant qui indique
l'élément qui suit un élément de la liste. Au niveau de ce type de liste, le suivant
de la queue est la tête de la liste.
- Liste circulaire avec chaînage double exprimé par le pointeur suivant qui indique
l'élément qui suit un élément de la liste et le pointeur precedent qui indique
l'élément qui précède un élément de la liste. Au niveau de ce type de liste, le
suivant de la queue est la tête de la liste et le précédent de la tête est la queue de
la liste.

47 sur 64
Par: mme Olfa HAMROUNI JEMLI

Chapitre 13: LES FILES D'ATTENTE ET LES PILES

1. Les files d'attente


1.1. Définition
Une file d'attente est une structure de données telle que:
- L'ajout d'un élément se fait en fin de file
- La suppression d'un élément se fait au début de file
Cette structure de données est appelée FIFO (First In First Out= Premier Entré Premier
Sorti).
Une file d'attente peut être considérée comme une liste, mais une liste à caractère FIFO.
La gestion d'une file se base sur les actions suivantes:
- Création d'une file via la fonction CreerFile
- Test si une file est vide ou non via la fonction EstVideFile
- Enfilement d'un élément dans une file. Il s'agit de l'ajout d'un élément via la
fonction Enfiler
- Défilement d'un élément d'une file. Il s'agit de la suppression d'un élément via la
fonction Defiler
- Destruction d'une file via la fonction DetruireFile
- Affichage du contenu de la file via la fonction ListerFile.
La déclaration d'une file peut se baser sur la représentation statique (utilisation des
tableaux), ou sur la représentation dynamique (utilisation des pointeurs). Dans ce qui
suit, on se basera sur la représentation dynamique.

1.2. Le module de gestion de file d'attente


Le fichier en-tête déclarant une file et spécifiant ses fonctions peut s'inspirer du module
de gestion de liste étant donné qu'une file n'est qu'un cas particulier d'une liste.
Le fichier en-tête de la gestion de file d'attente nommé file.h ressemble au suivant:

typedef struct element * PElement;


typedef struct element
{
int e;
PElement suivant;
} Element;

48 sur 64
Par: mme Olfa HAMROUNI JEMLI

typedef struct file


{
PElement tete;
PElement queue;
} TFile;

void CreerFile (TFile * F);


int EstVideFile(TFile F); //cette fonction teste si la file d'attente F est vide(1) ou non(0)
void Enfiler (TFile * F, int N); //cette fonction insère un élément N en fin de la file
d'attente F
int Defiler (TFile * F); //cette fonction renvoie l'élément existant en tête de la file
d'attente F, // ensuite, elle le supprime
void DetruireFile(TFile * F); //cette fonction supprime tous les éléments de la file
d'attente F
void ListerFile(TFile F); //cette fonction affiche tous les éléments de la file d'attente F

L'implémentation du fichier file.h est élaborée dans le fichier source file.c suivant:
#include <stdio.h>
#include <stdlib.h>
#include "file.h"

void CreerFile (TFile * F)


{
F->tete=NULL;
F->queue=NULL;
}
///////////////////////////////////////////////
int EstVideFile(TFile F)
{
if (F.tete==NULL) return(1);
else return (0);
}
///////////////////////////////////////////////
void Enfiler (TFile * F, int N)
{
{
PElement ptr;

49 sur 64
Par: mme Olfa HAMROUNI JEMLI

ptr=malloc(sizeof(Element));
ptr->e=N;
if (F->tete==NULL)
F->tete=ptr;
else
F->queue->suivant=ptr;
ptr->suivant=NULL;
F->queue=ptr;
}
}
///////////////////////////////////////////////
void ListerFile(TFile F)
{
PElement ptr;
ptr=F.tete;
while (ptr!=NULL)
{printf("\n%d", ptr->e);
ptr=ptr->suivant;
}
}
///////////////////////////////////////////////
int Defiler (TFile * F)
{
PElement aux;
int Elem;
if (EstVideFIle(*F)) puts("Liste vide");
else
if (F->tete==F->queue)
{
Elem=F->tete->e;
free(F->tete);
F->tete=NULL;
F->queue=NULL;
return(Elem);
}
else
{
aux=F->tete;

50 sur 64
Par: mme Olfa HAMROUNI JEMLI

F->tete=F->tete->suivant;
Elem=aux->e;
free(aux);
return(Elem);
}
}
///////////////////////////////////////////////
void DetruireFile(TFile * F)
{
int x;
while(!EstVideFile(*F))
{
x=Defiler(F);
printf("\nLa valeur détruite maintenant est:%d\n",x);
}
printf("Liste detruite");
}

2. Les piles
1.1. Définition
Une pile est une structure de données telle que:
- L'ajout d'un élément se fait au sommet de la pile
- La suppression d'un élément se fait également au sommet de la pile
Cette structure de données est appelée LIFO (Last In First Out= Dernier Entré Premier
Sorti).
Une pile peut être considérée comme une liste, mais une liste à caractère LIFO. La
gestion d'une pile se base sur les actions suivantes:
- Création d'une pile via la fonction CreerPile
- Test si une pile est vide ou non via la fonction EstVidePile
- Empilement d'un élément dans une pile. Il s'agit de l'ajout d'un élément via la
fonction Empiler
- Dépilement d'un élément d'une pile. Il s'agit de la suppression d'un élément via la
fonction Depiler
- Destruction d'une pile via la fonction DetruirePile
- Affichage du contenu de la pile via la fonction ListerPile.
La déclaration d'une pile peut se baser sur la représentation statique (utilisation des
tableaux), ou sur la représentation dynamique (utilisation des pointeurs). Dans ce qui
suit, on se basera sur la représentation dynamique.

51 sur 64
Par: mme Olfa HAMROUNI JEMLI

1.2. Le module de gestion de pile


Le fichier en-tête déclarant une pile et spécifiant ses fonctions peut s'inspirer du module
de gestion de liste étant donné qu'une pile n'est qu'un cas particulier d'une liste.
Le fichier en-tête de la gestion de pile nommé pile.h ressemble au suivant:
typedef struct element * PElement;
typedef struct element
{
int e;
PElement suivant;
} Element;
typedef struct pile
{
PElement sommet;
} TPile;

void CreerPile (TPile * P); //cette fonction crée une pile nommée P
int EstVidePile(TPile P); //cette fonction teste si la pile P est vide(1) ou non(0)
void Empiler (TPile * P, int N); //cette fonction insère un élément N au sommet de la
pile P
int Depiler (TPile * P); //cette fonction renvoie l'élément existant au sommet de la pile
P, //ensuite, elle le supprime
void DetruirePile(TPile * P); //cette fonction supprime tous les éléments de la pile P
void ListerPile(TPile P); //cette fonction affiche tous les éléments de la pile P

L'implémentation du fichier pile.h est élaborée dans le fichier source pile.c suivant:
#include <stdio.h>
#include <stdlib.h>
#include "pile.h"
////////////////////////////////////////
void CreerPile (TPile * P)
{
P->sommet=NULL;
}
////////////////////////////////////////
int EstVidePile(TPile P)

52 sur 64
Par: mme Olfa HAMROUNI JEMLI

{
return(P.sommet==NULL);
}
////////////////////////////////////////
void Empiler (TPile * P, int N)
{
PElement ptr;
ptr=malloc(sizeof(Element));
ptr->e=N;
if (EstVidePile(*P))
{
P->sommet=ptr;
ptr->suivant=NULL;
}
else
{
ptr->suivant=P->sommet;
P->sommet=ptr;
}
}
///////////////////////////////////////
void ListerPile(TPile P)
{
PElement ptr;
ptr=P.sommet;
while( ptr!=NULL)
{
printf("%d\n",ptr->e);
ptr=ptr->suivant;
}
}
///////////////////////////////////////
int Depiler (TPile * P)
{
PElement aux;
int Elem;
if (P->sommet==NULL) puts("Liste vide");
else

53 sur 64
Par: mme Olfa HAMROUNI JEMLI

{
Elem=P->sommet->e;
aux=P->sommet;
P->sommet=P->sommet->suivant;
free(aux);
return(Elem);
}
}
////////////////////////////////////////
void DetruirePile(TPile * P)
{
int val;
while (!EstVidePile(*P))
{
val=Depiler(P);
printf("L'element retire est:%d",val);
}
printf("\nPile rechargée");
}

54 sur 64
Par: mme Olfa HAMROUNI JEMLI

Chapitre 14: LES ARBRES

1. Introduction
Un arbre est un ensemble fini d'éléments à un e structure hiérarchique. Chaque élément
est appelé un nœud. Chaque nœud contient l'information spécifique à l'application et des
pointeurs vers d'autres nœuds (d'autres sous-arbres).
Terminologie:
- Une feuille: est un nœud qui ne pointe vers aucun autre nœud.
- Une racine: est le nœud de niveau 1 qui n'est pointé par aucun autre nœud.
- Un niveau: La racine a le niveau 1. les autres nœuds ont un niveau qui est augmenté
de 1 par rapport au nœud dont ils dépendent.
- Une arête: est un lien entre deux meuds.
- Un chemin: est une suite d'arêtes successives.
- Une branche: est un chemin qui se termine par une feuille.
- Une hauteur ou une profondeur: est le niveau maximum atteint par la branche la plus
longue.
- Un degré d'un nœud: est le nombre de successeurs.
- Une taille: est le nombre total de nœuds de l'arbre.

Exemple d'arbre: Arbre de lettres en majuscule


- D, E, G et I sont des feuilles
- A est la racine
A
- Le niveau de A est: 1
- Le niveau de I est: 5
B C
- La hauteur de l'arbre est: 5
- Le degré de la racine est: 2

D E F - Le degré de I est: 1
- La taille de l'arbre est: 9
- Exemples d'arêtes: AC, FG, HI
G H - Exemples de branches: FHI, ABE
- Exemples de chemin: ACF, ACFG
I

55 sur 64
Par: mme Olfa HAMROUNI JEMLI

Autres exemples d'arbres:


- Arbre syntaxique d'une phrase française
- Arbre généalogique
- Arbres des répertoires et des fichiers d'un système d'exploitation
- Arbre d'une expression arithmétique
- Arbre de répartition des animaux.
- Etc.

2. Les arbres binaires


2.1. Définition
Un arbre binaire est un arbre tel que chaque nœud a au plus 2 fils, et quand il n'y en a
qu'un, on distingue le fils gauche du fils droit.

2.2. Mémorisation d'un arbre binaire


Elle peut se faire soit en allocation dynamique soit en allocation contiguë.
 Allocation dynamique
La création d'un nœud se fait au fur et à mesure des besoins. Chaque nœud est
constitué de l'information, de l'adresse du fils gauche et de l'adresse du fils droit.
Exemple: Reprenons l'exemple de l'arbre des lettres en majuscules

B C

D E F NULL

NULL NULL NULL NULL G H

I NULL

NULL NULL

56 sur 64
Par: mme Olfa HAMROUNI JEMLI

On suppose déclarer l'arbre ci-dessus, La déclaration ressemblera à la suivante:


typedef struct Noeud * PNoeud;
typedef struct Noeud
{
char Info;
PNoeud fg;
PNoeud fd;
}TNoeud;
typedef struct arbre
{
PNoeud racine;
PNoeud Courant;
}TArbre;

 Allocation contiguë
L'allocation peut se faire aussi avec des tableaux:

Exemple: Reprenons l'exemple de l'arbre des lettres en majuscules


Info fg fd
A B C
B D E
C F /
D / /
E / /
F G H
G / /
H I /
I / /

On suppose déclarer l'arbre ci-dessus, La déclaration ressemblera à la suivante:


Struct Nœud
{
char Info;
char fg;
char fd;
} Tnoeud;
TNoeud Arbre[9];

2.3. Opérations sur les arbres binaires

57 sur 64
Par: mme Olfa HAMROUNI JEMLI

Soit la représentation dynamique et soit la déclaration d'un arbre binaire vue ci-dessus,
les opérations qui s'appliquent sur un arbre binaire sont:

a- Création d'un arbre


Cette fonction permet de créer un arbre binaire.
void CreerArbre(TArbre * A)
{
A->Courant=NULL;
A->racine=NULL;
}

b- Test si un arbre est vide ou non


Cette fonction permet de tester si un arbre binaire est vide (valeur de retour est 1) ou
non ( valeur de retour est 0).
int ArbreVide (TArbre A)
{
return(A.racine==NULL);
}

c- Modification du nœud courant


Cette fonction permet de modifier l'information Info du nœud courant par une
information fournie en paramètre.
void ModifCourant(TArbre* A, int N)
{
if (A->Courant!=NULL)
A->Courant->Info=N;
}

d- Suppression du sous-arbre dont la racine est le nœud courant


void SuppressionSousArbre(TArbre * A)
{
if (A->Courant!=NULL)
free(A->Courant);
}

e- Insertion d'un élément pour être soit un fils gauche du nœud


courant, soit son fils droit

58 sur 64
Par: mme Olfa HAMROUNI JEMLI

Cette fonction permet d'insérer un élément portant l'information N dans l'arbre A au


niveau niveau. Le niveau peut être g ou G si l'insertion se fera au niveau du fils gauche et
d ou D si l'insertion se fera au niveau du fils droit.
void InsererElement(TArbre * A, int N, char niveau)
{
PNoeud p;
p=malloc(sizeof(PNoeud));
p->Info=N;
p->fd=NULL;
p->fg=NULL;
if (A->racine==NULL)
{
A->racine=p;
A->Courant=p;
}
else
{
switch (niveau)
{
case 'g':
case 'G':{
if(A->Courant->fg!=NULL) puts("Insertion impossible");
else A->Courant->fg=p;
break;
}
case 'd':
case 'D':{
if(A->Courant->fd!=NULL) puts("Insertion impossible");
else A->Courant->fd=p;
break;
}
}
A->Courant=p;
}
}

f- Recherche récursive d'un élément


Cette fonction permet de renvoyer le nœud portant l'information x. la recherche
commence à partir du nœud racine.

59 sur 64
Par: mme Olfa HAMROUNI JEMLI

PNoeud RechercheNoeud(PNoeud racine, int x)


{
PNoeud p;
if (racine==NULL) p=NULL;
else if (racine->Info==x) p=racine;
else
{
p=RechercheNoeud(racine->fg,x);
if (p==NULL) p=RechercheNoeud(racine->fd,x);
}
return(p);
}

g- Recherche récursive de la taille d'un arbre


Cette fonction renvoie le nombre de nœuds de l'arbre. La recherche commence à partir
du nœud racine.
int TailleArbre(PNoeud racine)
{
if (racine==NULL) return(0);
else
return(1+TailleArbre(racine->fg)+TailleArbre(racine->fd));
}

h- Test si un nœud est une feuille


Cette fonction teste si un nœud est une feuille(valeur de retour est 1) ou non( valeur de
retour est 0)
int Feuille(PNoeud N)
{
return((N->fg==NULL) && (N->fd==NULL));
}

i- Calcul récursif du nombre de feuille


int NbreFeuille(PNoeud racine)
{
int N;
if (racine==NULL) N=0;
else if (Feuille(racine)) N=1;
else N=NbreFeuille(racine->fg)+NbreFeuille(racine->fd);

60 sur 64
Par: mme Olfa HAMROUNI JEMLI

return(N);
}

j- Listing récursif de toutes les feuilles


void ListingArbre(PNoeud racine)
{
if (racine!=NULL)
{
if (Feuille(racine)) printf("\n%d",racine->Info);
ListingArbre(racine->fg);
ListingArbre(racine->fd);
}
}

2.4. Parcours d'un arbre binaire


Le parcours d'un arbre est un procédé permettant d'accéder à chaque nœud de l'arbre
pour un traitement bien déterminé (en général, il s'agit d'un affichage). On distingue 2
catégories de parcours d'arbre: le parcours en profondeur et le parcours en largeur.
Dans ce qui suit, nous n'allons voir que le parcours en profondeur.

 Le parcours en profondeur
Pour parcourir l'arbre en profondeur, il faut préciser l'ordre de parcours. On distingue
entre le parcours préfixé( en préordre), le parcours infixé( en inordre) et le parcours en
postfixé (en postordre).

1- Le parcours préfixé
Il consiste à traiter la racine, à parcourir en préfixé le sous-arbre gauche et enfin à
parcourir en préfixé le sous-arbre droit.

Exemple: soit l'arbre suivant

B C

D I J 61 sur 64
Par: mme Olfa HAMROUNI JEMLI

En parcours préfixé, ce qui sera affiché est : ABDEGHFCIJK


En se basant sur la même déclaration déjà vue,(sauf que le type de Info sera char), le
code de la fonction Prefixe est:
void Prefixe(PNoeud racine)
{
if (racine!=NULL)
{
printf("%c",racine->Info);
Prefixe(racine->fg);
Prefixe(racine->fd);
}
}
2- Le parcours infixé
Il s'agit de parcourir en infixe le sous-arbre gauche, ensuite traiter la racine et enfin
traiter en infixe le sous-arbre droit.
Avec le même arbre binaire fourni ci-dessus, le résultat affiché sera: GEHDFBAICJK
la fonction Infixe est:
void Infixe(PNoeud racine)
{
if (racine!=NULL)
{
Infixe(racine->fg);
printf("%c",racine->Info);
Infixe(racine->fd);
}
}

3- Le parcours postfixé

62 sur 64
Par: mme Olfa HAMROUNI JEMLI

Il s'agit de parcourir en postfixé le sous-arbre gauche, ensuite parcourir en préfixé le


sous-arbre droit et ensuite traiter la racine.
Avec le même arbre binaire fourni ci-dessus, le résultat affiché sera: GHEFDBIKJCA
la fonction Postfixe est:
void Postfixe(PNoeud racine)
{
if (racine!=NULL)
{
Postfixe(racine->fg);
Postfixe(racine->fd);
printf("%d-",racine->Info);
}
}

63 sur 64
Par: mme Olfa HAMROUNI JEMLI

BIBLIOGRAPHIE
 Kyle LOUDON, traduction d'Eric JACOBONI, ALGORITHMES EN C, O'Reilly &
Associates, Paris 2000,2001, 2002
ISBN: 2-84177-096-6

 ClaudeDELANNOY, EXERCICES EN LANGAGE C, Eyrolles, Quatrième tirage 2000


ISBN: 2-212-08984-8

 Peter AITKEN & Bradley L. JONES, LE LANGAGE C, Campus Press, France 2000
ISBN: 2-7440-0838-9

 Claude DELANNOY, PROGRAMMER EN LANGAGE C, Eyrolles 1997


ISBN: 2-212-11072-3

 Michael GRIFFITHS, ALGORITHMIQUE ET PROGRAMMATION, Hernes, 1992


ISBN: 2-86601-323-9

 Jacques COURTIN & Irène KOWARSKI, INITIATION A L'ALGORITHMIQUE ET AUX


STRUCTURES DE DONNEES, Dunod, 1994
ISBN: 2-10-004039-1

 Guy PIERRA, LES BASES DE LA PROGRAMMATION ET DU GENIE LOGICIEL, Dunod,


1991
ISBN: 2-04-020722-8

 Claude DELANNOY, LANGAGE C, Eyrolles, 1999, 2002


ISBN: 2-212-11123-1

 Pc Poche, LANGAGE C, Micro Application, 2000, 20001


ISBN: 2-7429-2008-0

64 sur 64

Vous aimerez peut-être aussi