Vous êtes sur la page 1sur 41

Module: Structures de données

Pr. Abdelkaher AIT ABDELOUAHAD

Institut National de Statistique et d’Économie Appliquée

a.abdelkaher@gmail.com

06 Février 2023

Pr. A. AIT ABDELOUAHAD INSEA


Objectifs du cours

Étudier les structures de données les plus utilisées en


programmation

Être capable de choisir la structure adéquate à chaque


problème

Être familiarisé à la résolution des problèmes algorithmiques

Pouvoir implémenter les structures de données en C

Pr. A. AIT ABDELOUAHAD INSEA


Pré requis

Algorithmique

Programmation en langage C

Pr. A. AIT ABDELOUAHAD INSEA


Contenu

Concepts de base

Nouveaux types et synonymes

Type abstrait de données

Pile

File

Liste

Arbres

Graphes

Pr. A. AIT ABDELOUAHAD INSEA


Bibliographie

L’essentiel des structures de données en C. Ellis Horowitz,


Sartaj Sahni. Dunod 1993

Algorithmes et Structures De Données Génériques : Cours Et


Exercices Corrigés en Langage C. Michel Divay, Dunod 2004

Initiation à l’algorithmique et à la Programmation en C. Rémy


Malgouyres, Rita Zrour, Fabien Feschet. 2 ème édition 2011.

Programmer en C. Claude DELANNOY, 5 ème édition 2009,


Eyrolles.

Pr. A. AIT ABDELOUAHAD INSEA


Partie 1 : Concepts de base

Pr. A. AIT ABDELOUAHAD INSEA


Plan

1 Algorithmes
I Représentations des algorithmes
I Pseudo langage
I Codage d’un algorithme

2 Programmation en C
I Généralités
I Pointeur et tableau
I Les fonctions
I La récursivité

Pr. A. AIT ABDELOUAHAD INSEA


Algorithmes
Un algorithme est une description complète et détaillée des
actions à effectuer et de leur séquencement pour arriver à un
résultat donné
I Intérêt : séparation analyse/codage (pas de préoccupation de
syntaxe)
I Qualités : exact (fournit le résultat souhaité), efficace (temps
d’exécution, mémoire occupée), clair (compréhensible), général
(traite le plus grand nombre de cas possibles),...
L’algorithmique désigne aussi la discipline qui étudie les
algorithmes et leurs applications en Informatique
Une bonne connaissance de l’algorithmique permet d’écrire des
algorithmes exacts et efficaces
Exemples :
I Une recette de cuisine est un algorithme, l’entrée étant les
ingrédients et la sortie le plat cuisiné.
I L’algorithme d’Euclide : c’est un algorithme permettant de
déterminer le plus grand commun diviseur (P.G.C.D.) de deux
entiers
Pr. A. AIT ABDELOUAHAD INSEA
Représentations des algorithmes

Historiquement, deux façons pour représenter un algorithme :

L’organigramme : représentation graphique avec des symboles


(carrés, losanges, etc.)
I offre une vue d’ensemble de l’algorithme

I représentation quasiment abandonnée aujourd’hui

Le pseudo-code : représentation textuelle avec une série de


conventions ressemblant à un langage de programmation (sans
les problèmes de syntaxe)
I plus pratique pour écrire un algorithme

I représentation largement utilisée

Pr. A. AIT ABDELOUAHAD INSEA


Pseudo langage

Structures élémentaires d’un pseudo langage :


1 Entrées/Sorties : Lire, Écrire
2 Affectation : X ←Y
3 Instructions conditionnelles :

Si condition Alors instructions FinSi


Si condition Alors instructions1 Sinon instructions2 FinSi

4 Instructions répétitives (les boucles)

TantQue condition Faire instructions FinTantQue


Faire instructions TantQue condition
Pour i=0 à n Faire instructions FinPour

Pr. A. AIT ABDELOUAHAD INSEA


Pseudo langage

Calculer la factorielle de N
Ecrire("saisissez le nombre :")
Lire (N)
F←1
Pour I=1 à N Faire F← F × I
FinPour
Ecrire(F)

Remarque
Il n’existe pas de formalisme universel pour l’écriture d’un pseudo
programme.

Pr. A. AIT ABDELOUAHAD INSEA


Codage d’un algorithme

Traduire l’algorithme dans un langage de programmation pour


pouvoir l’exécuter sur un ordinateur.

Chaque instruction élémentaire sera traduite dans le langage


de programmation.

Il faut choisir la façon de représenter les données (structures


de données).

Pour résoudre un problème : nombreux algorithmes possibles.

Pour chaque algorithme : plusieurs choix de structures de


données.

Pr. A. AIT ABDELOUAHAD INSEA


Cas du langage C

Structures élémentaires :
1 Entrées/Sorties : scanf(), printf()
2 Affectation : X =Y
3 Instructions conditionnelles :

if condition instructions
if condition instructions1 else instructions2

4 Instructions répétitives (les boucles)

while condition instructions


do instructions while condition
for (i=0 ; i<n ; i++) instructions

Pr. A. AIT ABDELOUAHAD INSEA


Premier programme C

Pr. A. AIT ABDELOUAHAD INSEA


Les variables

Une variable possède :


I Un nom (identificateur)
I Un type
I Une valeur
Le nom d’une variable est fixe ; c’est ce qui caractérise la
variable. De même, le type d’une variable est fixe. Mais sa
valeur peut être modifiée.
Dans le nom des variables, on distingue majuscules et
minuscules ; donc toto et Toto sont deux variables différentes.
Un nom de variable commence toujours par une lettre. Les
autres caractères peuvent être des lettres, des chiffres ou le
tiret de soulignement : _.
Des noms de variables trop courts manquent souvent de sens,
et rendent le programme peu compréhensible. Des noms de
variables trop longs rendent le programme illisible.

Pr. A. AIT ABDELOUAHAD INSEA


Déclaration des variables

Pour être utilisée, une variable doit être déclarée. Pour déclarer
une variable, il faut donner son type, son nom, puis,
éventuellement une valeur initiale.

On appelle type de base les types déjà définis dans le langage :


I char : les caractères (un seul symbole)
I int : les entiers
I short : encore des entiers
I long : toujours des entiers
I float : les décimaux
I double : encore des décimaux
I long double : et toujours des décimaux

Deux types de variables :


I Locales : à l’intérieur d’une fonction
I Globales : déclarées au début du fichier

Pr. A. AIT ABDELOUAHAD INSEA


Les pointeurs

Un pointeur est une variable spéciale qui peut contenir


l’adresse d’une autre variable.

L’adresse mémoire d’une variable est donnée par l’opérateur


unaire & : adresse de la variable a est &a

Si un pointeur pa contient l’adresse d’une variable A, on dit


que ’pa pointe sur A’.

Pr. A. AIT ABDELOUAHAD INSEA


Les pointeurs

En C, l’utilisation de pointeurs est incontournable car ils sont


étroitement liés à la représentation des tableaux. Ils sont aussi utiles
dans différentes situations :

Passage par adresse pour des paramètres des fonctions

Allocation dynamique de la mémoire

Gestion des fichiers

Réalisation des structures de données récursives (listes et


arbres)

...

Pr. A. AIT ABDELOUAHAD INSEA


Les pointeurs

En C, on déclare un pointeur par l’instruction : type *nom_


du_ pointeur ; où
I type est le type de la variable pointée,
I l’identificateur nom_ du_ pointeur est le nom de la variable
pointeur.
I * est l’opérateur qui indiquera au compilateur que c’est un
pointeur.

int *p ; char *c ; float *q ;

Initialisation
Pour récupérer l’adresse d’une variable A et la mettre dans le
pointeur P ( P pointe vers A ) :

int A=10, *P ;
P=&A ;

Pr. A. AIT ABDELOUAHAD INSEA


Les pointeurs

En C, un pointeur correspond à la fois à une adresse en


mémoire et à un type (nombre d’octets référencés).

int a=1025;
int *p=&a;
printf("%d",*p); // chercher le contenu de 4 octets
// a partir de l’adresse 200 ---> 1025
char *p0=(char*)p; // p0 contient la meme adresse que p
printf("%d",*p0); // chercher le contenu de 1 octet
// a partir de l’adresse 200 ---> 1

Pr. A. AIT ABDELOUAHAD INSEA


Les tableaux

La déclaration : Type Nom_Tableau[taille] ;

Exemple : int t[20] ;


réserve l’emplacement pour 20 éléments de type int.

Remarques :
I Chaque élément est repéré par sa position dans le tableau,
nommée indice, en langage C, la première position porte le
numéro 0.
I Dans l’exemple, les indices vont de 0 à 19.
I Le premier élément du tableau sera désigné par t[0],
I le troisième par t[2],
I le dernier par t[19].
I La notation &t[i] désigne l’adresse de cet élément t[i]

Pr. A. AIT ABDELOUAHAD INSEA


Les fonctions

En C, une fonction est définie par


I son nom
I son type de de retour
I le nombre et le type de ses paramètres (ou arguments)
I son corps (contenu)

type nom (type1 arg1,..., typeN argN)


{
...
instructions ;
...
return exp ;
}

On définit une fonction en dehors de la fonction principale


main() (avant ou après).

Pr. A. AIT ABDELOUAHAD INSEA


Les fonctions

maximum
int maximum (int a, int b)
{
int max;
if (a>b)
max = a;
else
max = b;
return max;
}

somme
double Som(double x, double y)
{
return (x+y);
}

Pr. A. AIT ABDELOUAHAD INSEA


Les fonctions

L’appel d’une fonction se fait par simple écriture de son nom


avec la liste des paramètres :
nom_fonction (para1,..., paraN) ;

Lors de la définition, les paramètres sont appelés :


I paramètres formels

Lors de l’appel d’une fonction, les paramètres sont appelés :


I paramètres effectifs : ils contiennent les valeurs pour effectuer
le traitement

L’ordre et les types des paramètres effectifs doivent


correspondre à ceux des paramètres formels

Pr. A. AIT ABDELOUAHAD INSEA


Exemples d’appels

Appel des fonctions : max, som et afficheTab

int main()
{
// declaration des variables
int c,x=20,y=19;
double z;
int A[5] = {1, 2, 3, 4, 5};
// appels des fonctions max, som
c = maximum( x, y);
printf("max(%d,%d)=%d",x,y,c);
c = maximum(12,15);
z=Som(2.5, 7.3);
AfficheTab(A,5);
return 0;
}

Pr. A. AIT ABDELOUAHAD INSEA


Allocation dynamique de mémoire

La déclaration d’un tableau définit un tableau "statique"

I int tab[10] ;

I besoin d’espace mémoire d’avantage ou gaspillage d’espace


mémoire (réservation de l’espace maximal prévisible )

Problème : espace mémoire (nombre d’éléments à saisir) est


connu au moment de l’exécution

Solution : allocation dynamique de la mémoire

Il est possible de demander d’allouer dynamiquement un


certain nombre d’octets avec la fonction malloc.

Pr. A. AIT ABDELOUAHAD INSEA


Allocation dynamique de mémoire

Le prototype de la fonction malloc :

void* malloc( unsigned int size) ;

L’appel à la fonction "malloc"

I alloue size octets pour le programme

I retourne un pointeur vers l’espace alloué ou retourne NULL s’il


n’est pas possible d’allouer de la mémoire
Désallocation de l’espace mémoire
I La procédure "free"

void free(void *p) ;

Pr. A. AIT ABDELOUAHAD INSEA


Allocation dynamique de mémoire
Chronologie
I on déclare un pointeur sur un type donné : Type *p ;
I on alloue un certain nombre d’octets (correspondant à un
multiple de la taille en octet de Type) :
I p =(Type*) malloc(n*sizeof(Type)) ;
I on vérifie que malloc n’a pas renvoyé NULL
I on utilise l’espace données alloué et à la fin, on le libère.

Exemple
int * p;
p = (int *) malloc ( 10* sizeof (int) );
if(p!=NULL)
for(i=0; i <10; i++)
scanf ("\%d",p+i);
free(p);

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions récursives

En informatique, la récursivité est un des concepts de


programmation les plus importants.
Elle permet de résoudre des problèmes complexes en les
décomposant en problèmes plus petits
Une procédure (ou fonction) est dite récursive lorsqu’elle fait
appel à elle même.
C’est l’équivalent de la récurrence en mathématique.
La programmation récursive sert à remplacer les boucles
(while, for, ..., etc).
Il faut vérifier si le processus ne boucle pas indéfiniment.
Une procédure ou fonction récursive peut s’appeler plusieurs
fois.

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions récursives
Le langage C autorise la récursivité des appels de fonctions.
Celle-ci peut prendre deux aspects :
I récursivité directe : une fonction comporte, dans sa définition,
au moins un appel à elle-même.
I récursivité croisée : l’appel d’une fonction entraîne celui d’une
autre fonction qui, à son tour, appelle la fonction initiale (le
cycle pouvant d’ailleurs faire intervenir plus de deux fonctions).

Principes de programmation : l’écriture de fonctions récursives


demande à vérifier deux propriétés :
I Correction : La décomposition récursive d’un problème en
sous-problèmes donne en général un algorithme dont la
correction est simple à prouver.
I Terminaison : Il faut vérifier que les cas terminaux prennent
bien en compte toutes les valeurs non traitées dans les appels
récursifs.
Pr. A. AIT ABDELOUAHAD INSEA
La recette de récursivité

S’assurer que le problème peut se décomposer en un ou


plusieurs sous-problèmes de même nature.

Identifier le cas de base qui est le plus petit problème qui ne se


décompose pas en sous-problèmes

Résoudre(P) =

I si P est un cas de base, le résoudre directement. Sinon :


I décomposer P en sous-problèmes P1, P2,...
I résoudre récursivement P1, P2,...
I combiner les résultats pour obtenir la solution pour P

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions récursives

Un exemple fort classique d’une fonction calculant une


factorielle de manière récursive :

Fonction récursive de calcul de factorielle


long fac (int n)
{
if (n>0) return (fac(n-1)*n) ;
else return(1) ;
}

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions récursives

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions récursives

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions récursives

Remarques
Chaque appel de fac entraîne une allocation d’espace pour les
variables locales et pour son argument n (apparemment, fct ne
comporte aucune variable locale ; en réalité, il lui faut prévoir
un emplacement destiné à recevoir sa valeur de retour)
Chaque nouvel appel de fac,à l’intérieur de fac, provoque une
telle allocation, sans que les emplacements précédents soient
libérés.
Il y a donc un empilement des espaces alloués aux variables
locales, parallèlement à un empilement des appels de la
fonction
Ce n’est que lors de l’exécution de la première instruction
return que l’on commencera à « dépiler » les appels et les
emplacements et donc à libérer de l’espace mémoire.

Pr. A. AIT ABDELOUAHAD INSEA


Récursivité terminale

Définition
Une définition de fonction f est récursive terminale quand tout
appel récursif est de la forme return f(...) ; La valeur retournée est
directement la valeur obtenue par un appel récursif, sans qu’il n’y
ait aucune opération sur cette valeur.

somme(a,b)

int somme (int ab, int b){


if (b==0)
return a;
return somme(a+1,b-1);
}

somme(4,2)=somme(5,1)=somme(6,0)=6

Pr. A. AIT ABDELOUAHAD INSEA


Récursivité non terminale

Définition
L’appel récursif n’est pas la dernière instruction et/ou elle n’est pas
isolée (fait partie d’une expression).

somme(a,b)

int somme (int ab, int b){


if (b==0)
return a;
return 1+somme(a,b-1);
}

somme(4,2)=1+somme(4,1)=1+1+somme(4,0)=1+1+4=6

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions prédéfinies

<stdio.h>
int fputc(int C, FILE *FP)
int fgetc(FILE *FP)
int printf(const char *FORMAT, ...)
int scanf(const char *FORMAT, ...)
int putchar(int C)
int getchar(void)
int puts(const char *CH)
char *gets(char *CH)

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions prédéfinies

<string.h>

int strlen(const char *CH1)


char *strcpy(char *CH1, const char *CH2)
char *strncpy(char *CH1, const char *CH1, int N)
char *strcat(char *CH1, const char *CH1)
char *strncat(char *CH1, const char *CH1, int N)
int strcmp(const char *CH1, const char *CH1)

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions prédéfinies

<math.h>
double sin(double X)
double cos(double X)
double tan(double X)
double asin(double X)
double acos(double X)
double atan(double X)
double exp(double X)
double log(double X)
double log10(double X)
double pow(double X, double Y)
double sqrt(double X)
double fabs(double X)

Pr. A. AIT ABDELOUAHAD INSEA


Fonctions prédéfinies

<stdlib.h>
void *malloc(unsigned int N)
void *calloc(int c,unsigned int N)
void *realloc(void *P,unsigned int N)
void free(void *P)
int atoi(const char *CH)
long atol(const char *CH)
double atof(const char *CH)

Pr. A. AIT ABDELOUAHAD INSEA

Vous aimerez peut-être aussi