Conception de structures de donn´ ees
Cours 3 Types abstraits suivis de R´ecursion
11 mars 2013
Struct 1/24
Types abstraits
Struct 2/24
Types abstraits Implantation et utilisation R´ecursivit´e
D´ efinition
Un type abstrait est la sp´ecification d’un ensemble de donn´ees et de l’ensemble des op´erations qu’elles peuvent effectuer.
On dit qu’un tel type est abstrait parce qu’il est uniquement d´efinit par le cahier des charges qu’une structure de donn´ees doit ensuite impl´ementer.
B Pour utiliser un type abstrait, on ne doit absolument pas se servir de la fa¸ con dont il est impl´ ement´ e (on n’a d’ailleurs pas besoin de le savoir).
Exemples :
types Date et Heure et les fonctions pour les manipuler, type Ensemble (en TP),
types Polynˆome ou Matrice et leurs op´erations alg´ebriques, listes, piles, files, arbres binaires, ...
Struct 3/24
Types abstraits Implantation et utilisation R´ecursivit´e
Op´ erations sur les types abstraits
Les op´erations sont divis´ees en plusieurs types :
les constructeurs : ils permettent de cr´eer un nouvel
“objet” du type que l’on est en train de d´efinir. Il peut y avoir plusieurs constructeurs :
nouvel objet neutre ou vide, nouvel objet param´etr´e, nouvel objet al´eatoire, ...
les modificateurs : ils permettent de modifier les objets et leur contenu.
les observateurs : ils donnent des informations sur l’´etat de l’objet (valeurs, affichages, ...)
On ne manipule un type abstrait qu’avec les fonctions qui lui sont associ´ ees ! !
Struct 4/24
Types abstraits Implantation et utilisation R´ecursivit´e
Exemple du type Color
Fichier color.h :
typedef ... Color;
Color randomColor(void);
Color newColorRGB(int r, int g, int b);
void printRGB(Color c);
void printHexa(Color c);
Color grayScale(Color c);
Color mixColors(Color c1, Color c2);
void inverseColor(Color *c);
Programme principal :
#include "color.h"
int main (int argc, char *argv[]){
Color c1 = randomColor();
Color c2 = newColorRGB(255,0,0);
Color c3;
printRGB(c1);
printRGB(grayScale(c1));
printHexa(c2);
c3=mixColors(c1,c2);
printRGB(c3);
inverseColor(&c3);
printRGB(c3);
}
Struct 5/24
Types abstraits Implantation et utilisation R´ecursivit´e
Implantation et utilisation de types abstraits :
types structur´ es
Struct 6/24
Types abstraits Implantation et utilisation R´ecursivit´e
Struct
Les types structur´es sont un moyen privil´egi´e de d´efinir des types abstraits : ce sont des types complexes construits `a partir de types “plus simples” :
struct nomStructure { type champ1 nomChamp1;
type champ2 nomChamp2;
...
} ;
typedef nomStructure nomType ;
typedef struct {
type champ1 nomChamp1;
type champ2 nomChamp2;
...
} nomType ;
Si on d´efinit un pointeur sur une structure, la notation -> est un raccourci pour acc´eder aux champs :
typedef struct { double Re;
double Im;
} Complex;
Complex *c = &(Complex) { 0.3,1.2 } ; printf("%f+i*%fc", c->Re, c->Im);
Complex conjug = { c->Re,-c->Im } ;
Types abstraits Implantation et utilisation R´ecursivit´e
Le type Color - 1` ere version color.c
typedef struct { int hexa; }Color;
Color randomColor(void){
return (Color){myRand(0xffffff+1)};
}
Color newColorRGB(int r, int g, int b){
return (Color){(r<<16)+(g<<8)+b};
}
void printRGB(Color c){
printf("[%d,%d,%d] ",c.hexa>>16, (c.hexa & 0x00ff00)>>8 , (c.hexa & 0x0000ff));
}
void printHexa(Color c){
printf("#%x ", c.hexa);
}
Color grayScale(Color c){
int s=((c.hexa>>16) + ((c.hexa & 0x00ff00)>>8) + (c.hexa & 0x0000ff))/3;
Color res = {(s<<16)+(s<<8)+s};
return res;
}
Color mixColors(Color c1, Color c2){
return (Color){(c1.hexa+c2.hexa)/2};
}
void inverseColor(Color *c){
c->hexa=0xffffff-c->hexa;
}
Le type Color - 2` eme version color.c
typedef struct {
int red; int green; int blue;
}Color;
Color randomColor(void){
Color c={myRand(256), myRand(256), myRand(256)};
return c;
}
Color newColorRGB(int r, int g, int b){
Color c={r,g,b};
return c;
}
void printRGB(Color c){
printf("[%d,%d,%d] ",c.red, c.green, c.blue);
}
void printHexa(Color c){
printf("\#%x ", (c.red<<16) + (c.green<<8) + c.blue);
}
Color grayScale(Color c){
int s;
s=(c.red+c.blue+c.green)/3;
Color res = {s,s,s};
return res;
}
Color mixColors(Color c1, Color c2){
Color res;
res.red=(c1.red+c2.red)/2;
res.green=(c1.green+c2.green)/2;
res.blue=(c1.blue+c2.blue)/2;
return res;
}
void inverseColor(Color *c){
c->red=255-c->red;
c->green=255-c->green;
c->blue=255-c->blue;
}
Le programme principal (main) reste inchang´e... l’int´erˆet d’un type abstrait est que l’on peut l’utiliser, quelle que soit son impl´ementation, sans modifier les programmes qui y font appel.
Struct 9/24
Exemple du type SArray (tableaux tri´ es)
typedef ... SArray;
SArray newEmptySArray(void);
void printSArray(SArray t);
int getLength(SArray t);
int isEmpty(SArray t);
int isFull(SArray t);
int get(int i, SArray t);
int searchPosition(int elem, SArray t);
int search(int elem, SArray t);
void insertPosition(int elem, SArray *t, int i);
void delete(int i, SArray *t);
/***********************************************************/
void insert(int elem, SArray *t){
insertPosition(elem, t, searchPosition(elem,*t));
}
void randomSArray(int nb, SArray *t, int up){
int i;
for(i=0;i<nb;i++) insert(myRand(up),t);
}
Struct 10/24
Types abstraits Implantation et utilisation R´ecursivit´e
Exemple du type SArray - suite
int main (int argc, char *argv[]){
SArray t = newEmptySArray();
int i,j, up=20, taille=100;
srandom(time(NULL));
printSArray(t);
printf("t vide? %d, t plein? %d\n",isEmpty(t),isFull(t));
randomSArray(taille, &t, up);
printf("t vide? %d, t plein? %d\n",isEmpty(t),isFull(t));
printSArray(t);
printf("indice de %d dans t: %d\n", 1, search(1,t));
for(i=0;i<up;i++){
j=search(i,t);
printf("verification: get(search(%d,t),t): %d\n", i,j==-1?-1:get(j,t) );
}
while( (i=search(5, t)) != -1 ) delete(i, &t);
printf("longueur de t: %d\n", getLength(t));
printSArray(t);
}
Struct 11/24
Types abstraits Implantation et utilisation R´ecursivit´e
Exemple du type SArray - fin
typedef struct{ int lg; int tab[MAX SIZE]; }SArray;
SArray newEmptySArray(void){ SArray res;
res.lg=0;
return res;
}
void printSArray(SArray t){
printTab(t.tab, t.lg);
}
int getLength(SArray t){
return t.lg;
}
int isEmpty(SArray t){
return (t.lg==0);
}
int isFull(SArray t){
return (t.lg==MAX_SIZE);
}
int get(int i, SArray t){
if (i<0 || i>=t.lg)
erreur("L’indice %d est incorrect!", i);
return t.tab[i];
}
void insertPosition(int elem, SArray *t, int i){
...
}
void delete(int i, SArray *t){
...
}
int searchPosition(int e, SArray t){
return isEmpty(t)?0:searchPos(e,t.tab,0,t.lg-1);
}
int search(int elem, SArray t){
return dichoSearch(elem, t.tab, 0, t.lg-1);
}
Struct 12/24
Types abstraits Implantation et utilisation R´ecursivit´e
Exemple du type SArray - 2e fin
Ou alors...
typedef struct { int lg; int *tab; } SArray;
SArray newEmptySArray(void) { SArray res;
res.lg=0;
if( (res.tab=malloc(MAX SIZE*sizeof(int))) == NULL ) erreur("Allocation rat´ ee!");
return res;
} ...
Struct 13/24
Types abstraits Implantation et utilisation R´ecursivit´e
Un peu de r´ ecursivit´ e
Struct 14/24
Types abstraits Implantation et utilisation R´ecursivit´e
Structures r´ ecursives
Il est possible de cr´eer des structures de donn´ees r´ecursives, c’est-`a-dire qu’elles sont d´efinies en fonction d’elles-mˆemes (c’est le cas des listes, des arbres, ...).
! Il faut faire attention en d´efinissant de tels types : typedef struct {
int toto;
TR next;
} TR; /* FAUX ! */
typedef struct structRec { int toto;
struct structRec *next;
} TR; /* OK ! */
On ne peut pas d´efinir un type en fonction de lui-mˆeme ; Il faut que l’on puisse d´eterminer l’espace m´emoire
n´ecessaire `a la structure.
Rmq : les fonctions r´ecursives sont particuli`erement adapt´ees lorsque les structures qu’elles manipulent sont r´ecursives.
Types abstraits Implantation et utilisation R´ecursivit´e
Exemple du type Person
typedef struct person{
char *firstName; /* pr´enom */
char *lastName; /* nom */
struct person *father;
struct person *mother;
}Person;
Person *createPerson(char *f, char *l){
Person *h;
if ((h=malloc(sizeof(Person)))==NULL) error("Allocation rat´ee!");
h->firstName=f; h->lastName=l; h->father=NULL; h->mother=NULL;
return h;
}
Person *createPersonWithParents(char *f, char *l, Person *dad, Person *mum){
Person *h=createPerson(f,l);
h->father=dad; h->mother=mum;
return h;
}
Person *createPersonWithParentsNames(char *f, char *l, char *dad, char *mum){
Person *d=createPerson(dad,"");
Person *m=createPerson(mum,"");
return createPersonWithParents(f,l,d,m);
}
Types abstraits Implantation et utilisation R´ecursivit´e
Exemple du type Person - suite
void printName(Person *h){
printf("%s %s", h->firstName, h->lastName);
}
void printPerson(Person *h){
printf("%s %s ( p`ere: ", h->firstName, h->lastName);
(h->father==NULL)?printf("x"):printName(h->father);
printf("; m`ere: ");
(h->mother==NULL)?printf("x"):printName(h->mother);
printf(") ");
}
int main (int argc, char *argv[]){
Person *a = createPerson("Anabelle", "Curie");
printName(a); printf("\n");
Person *b = createPerson("Bernard", "Plank");
printName(b); printf("\n");
Person *c = createPersonWithParents("Clothilde", "Plank", b, a);
printPerson(c); printf("\n");
Person *d = createPersonWithParentsNames("Dany", "Newton", "Flint", "Fiona");
printPerson(d); printf("\n");
}
Struct 17/24
Types abstraits Implantation et utilisation R´ecursivit´e
Fonctions r´ ecursives
Struct 18/24
Types abstraits Implantation et utilisation R´ecursivit´e
Qu’est-ce qu’une fonction r´ ecursive ?
Une fonction qui s’appelle elle mˆeme... par exemple : void toto(int i) {
printf("%d ",i);
toto(i);
}
Il faut toujours s’assurer que la fonction termine ! void toto(int i) {
if(i>0) {
printf("%d ",i); toto(i-1);
} }
Pour r´esoudre le probl`eme P : si le probl`eme est suffisamment petit, on le r´esout directement, sinon on r´esout r´ecursivement un probl`eme plus petit pour arriver ` a la solution de P.
Struct 19/24
Types abstraits Implantation et utilisation R´ecursivit´e
Structure d’une fonction r´ ecursive
Comment ´ecrire la fonction r´ecursive int sumRec(int param) pour calculer la somme des entiers de 1 `a param ?
Il faut TOUJOURS un cas d’arrˆet : dans quel cas (pour quelle valeur de param) sait on r´esoudre le probl`eme directement ?
B if( n == 1 ) return 1;
Pour r´esoudre r´ecursivement, l’id´ee c’est d’imaginer que la fonction que l’on est en train d´ecrire existe d´ej` a et qu’on peut l’utiliser, `a condition que le param`etre soit ”plus petit” que param.
B int s = sumRec( param - 1 );
On utilise alors cette solution r´ecursive pour r´esoudre le probl`eme principal (de param`etre param).
B return param + s;
Struct 20/24
Types abstraits Implantation et utilisation R´ecursivit´e
Exemples de fonctions r´ ecursives
int sumRec(int param){ // somme des entiers de 1 ` a param if( param == 1 )
return 1;
else{
int s = sumRec( param - 1 );
return param + s;
} }
void printTab(int *tab, int lg){ // affiche un tab. d’entiers if ( lg == 1 )
printf("%d\n",tab[0]);
else{
printf("%d ",tab[0]);
printTab(tab+1, lg-1); // et si on inverse?
} }
Struct 21/24
Types abstraits Implantation et utilisation R´ecursivit´e
R´ ecursif vs. it´ eratif
Toutes les fonctions r´ecursives peuvent s’´ecrire de fa¸con it´erative et inversement :
int sumRec(int param){ // somme des entiers de 1 ` a param if( param == 1 )
return 1;
else{
int s = sumRec( param - 1 );
return param + s;
} }
int sumIte(int param){ // somme des entiers de 1 ` a param int i, s=0;
for( i=1; i<=param; i++) s+=i;
return s;
}
Struct 22/24
Types abstraits Implantation et utilisation R´ecursivit´e
R´ ecursif vs. it´ eratif nombres de Fibonacci
int fibo(int n){
int i, tmp, f1=1, f2=1;
for(i=3; i<=n; i++){
tmp=f2;
f2=tmp+f1;
f1=tmp;
}
return f2;
}
int fiboRec(int n){
if(n<=2) return 1;
else return fiboRec(n-1)+fiboRec(n-2);
}
Types abstraits Implantation et utilisation R´ecursivit´e