Vous êtes sur la page 1sur 32

UNIVERSITE PAUL SABATIER TOULOUSE III

Algorithmique, Structures de donnes e et langage C

L3 IUP AISEM/ICM
Janvier 2005

J.M. ENJALBERT

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Chapitre 1

Rappels et complments de C e
1.1 Structures

Une structure rassemble des variables, qui peuvent tre de types dirents, sous un seul nom e e ce qui permet de les manipuler facilement. Elle permet de simplier lcriture dun programme en e regroupant des donnes lies entre elles. e e Un exemple type dutilisation dune structure est la gestion dun rpertoire. Chaque che dun e rpertoire contient (par exemple) le nom dune personne, son prnom, son adresse, ses numros de e e e tlphone, etc... Le regroupement de toutes ces informations dans une structure permet de manipuler ee facilement ces ches. Autre exemple: On peut reprsenter un nombre complexe a laide dune structure. e ` On dnit une structure a laide du mot-cl: struct suivi dun identicateur (nom de la struce ` e ture) et de la liste des variables quelle doit contenir (type et identicateur de chaque variable). Cette liste est dlimite par des accolades. Chaque variable contenue dans la structure est appele e e e un champ ou un membre. Dnir une structure consiste en fait a dnir un nouveau type. On ne manipulera pas direce ` e tement la structure de la mme mani`re que lon ne manipule pas un type. On pourra par contre e e dnir des variables ayant pour type cette structure. e Exemple: struct complexe { double reel; double imag; }; struct complexe x,y; Dans cet exemple, on dnit une structure contenant deux rels puis on dclare deux variables e e e ayant pour type struct complexe. Les oprations permises sur une structure sont laectation (en considrant la structure comme e e un tout), la rcupration de son adresse (oprateur &) et lacc`s a ses membres. e e e e ` On acc`de a la valeur dun membre dune structure en faisant suivre lidenticateur de la variable e de type structure par un point suivi du nom du membre auquel on souhaite accder. Par exemple e x.reel permet daccder au membre reel de la variable x. e On peut initialiser une structure au moment de sa dclaration, par exemple: e struct complexe x={10,5}; On peut dnir des fonctions qui renvoie un objet de type structure. Par exemple, la fonction e suivante renvoie le complexe conjugu de x: e struct complexe conjugue(struct complexe x); { struct complexe y; 1

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

y.reel=x.reel; y.imag=-x.imag; return y; } Lutilisation de cette fonction pourra ressembler a: ` struct complexe x,z; z=conjugue(x); Laectation revient a aecter chaque membre de la structure, par exemple: ` struct complexe x,z; x=z; est quivalent a: e ` struct complexe x,z; x.reel=z.reel; x.imag=z.imag;

1.2

Types synonymes

Le langage C permet de crer de nouveaux noms de types de donnes grace a la fonction typedef. e e ` Par exemple: typedef int longueur fait du nom longueur un synonyme de int. La dclaration: e longueur l est alors quivalente a int l. e ` e Autre exemple, la dclaration typedef struct complexe comp,*p comp permet de crer deux e nouveaux mot-cls: comp quivalent a struct complexe et p comp quivalent a struct complexe* e e ` e ` (pointeur de struct complexe). Attention, un typedef ne cre pas de nouveaux types mais simplement de nouveaux noms pour e des types existants.

1.3
1.3.1

Pointeurs typs e
Prsentation e

A une variable correspond un emplacement mmoire caractris par une adresse et une longueur e e e (par exemple 4 octets conscutifs pour un long int). Cest, bien sur, le compilateur qui assure la e gestion de la mmoire et aecte a chaque variable un emplacement dtermin. On peut accder a e ` e e e la valeur de cette adresse grace a loprateur unaire & dit oprateur dadressage. ` e e Un pointeur est une variable dun type spcial qui pourra contenir ladresse dune autre variable. e On dit quil pointe vers cette variable. Celui-ci devra aussi conna tre le type de la variable vers laquelle il pointe puisque la taille dune variable (en octets) dpend de son type. La dclaration e e dun pointeur devra donc indiquer le type dobjet vers lequel il pointe (on dit dun pointeur quil est typ). La syntaxe est la suivante: e type *identificateur; Par exemple, pour dclarer un pointeur vers un entier on crira: e e int* p_entier; ou encore: int *p_entier; 2

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

On peut raliser des oprations sur des pointeurs de mme type. On peut en particulier aecter e e e a un pointeur un autre pointeur du mme type ou ladresse dune variable de mme type que celle ` e e du pointeur. On acc`de a la valeur stocke a ladresse contenue dans un pointeur grace a loprateur unaire e e ` ` e dit de rfrencement ou dindirection: * ee Dans lexemple suivant: int a; int* p_a; p_a=&a; *p a et a font rfrence au mme emplacement mmoire (et ont donc la mme valeur). ee e e e Un pointeur peut par ailleurs pointer vers un autre pointeur. On peut aussi incrmenter un pointeur. Cel` revient a augmenter sa valeur de la taille de lobjet e a ` point et donc a pointer sur lobjet suivant du mme type (sil en existe un!). e ` e La dclaration dun pointeur alloue un espace mmoire pour le pointeur mais pas pour lobjet e e point. Le pointeur pointe sur nimporte quoi au moment de sa dclaration. Il est conseill dinie e e tialiser tout pointeur avant son utilisation eective avec la valeur NULL (constante prdnie qui e e vaut 0) ce qui, par convention, indique que le pointeur ne pointe sur rien.

1.3.2

Pointeurs et tableaux

La dclaration dun tableau rserve de la place en mmoire pour les lments du tableau et e e e ee fournit une constante de type pointeur qui contient ladresse du premier lment du tableau. Cette ee constante est identie par lidenticateur donn au tableau (sans crochets). Cest cette constante e e de type pointeur qui va permettre de manipuler facilement un tableau en particulier pour le passer en param`tre dune fonction puisquon ne passera a la fonction que ladresse du tableau et non tous e ` ses lments. ee Lexemple suivant: int tab[10]; dclare un tableau de 10 lments. tab contient ladresse du premier lment et donc lexpression: e ee ee tab == &tab[0] est VRAIE. On a donc de mme: e *tab == tab[0] tab[1] == *(tab+1) tab[k] == *(tab+k) Les deux critures sont autorises. e e La dirence entre un tableau et un pointeur est quun tableau est une constante non modiable e alors quun pointeur est une variable.

1.3.3

Passage de param`tres ` une fonction e a

On a vu que les param`tres passs a une fonction le sont par valeur et ne peuvent pas tre e e ` e modis par lexcution de la fonction. Ceci est tr`s contraignant si lon souhaite quune fonction e e e renvoie plusieurs rsultats. Par exemple, si lon souhaite crire une fonction permuttant deux entiers, e e le code suivant qui parait correct ne fonctionnera pas: void permutation(int a, int b) { int c; c=a; a=b; b=c; } 3

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Lappel de la fonction: permutation(x,y); naura ainsi aucun eet sur x et sur y. La solution consiste a passer, pour les paramtres que lon souhaite voir modier par la fonction, ` e non plus les valeurs de ces param`tres mais les valeurs des adresses de ces param`tres. e e Les param`tres de la fonction devront donc tre des pointeurs. On acc`dera aux valeurs propee e e ment dites a lintrieur de la fonction gr`ce a loprateur dindirection *. ` e a ` e Si lon reprend lexemple prcdent, cela donne: e e void permutation(int* p_a, int* p_b) { int c; c=*p_a; *p_a=b; *p_b=c; } Remarque: on aurait pu garder les identicateurs initiaux a et b! Et lappel devra se faire en passant en param`tres les adresses des variables a modier gr`ce a e ` a ` loprateur dadressage &: e permutation(&x,&y);

1.3.4

Allocation dynamique

La dclaration de variables dans la fonction main ou globalement rserve de lespace en mmoire e e e pour ces variables pour toute la dure de vie du programme. Elle impose par ailleurs de conna e tre avant le dbut de lexcution lespace ncessaire aux stockage de ces variables et en particulier la e e e dimension des tableaux. Or dans de nombreuses applications le nombre dlments dun tableau ee peut varier dune excution du programme a lautre. e ` La biblioth`que stdlib fournit des fonctions qui permettent de rserver et de librer de mani`re e e e e dynamique (` lexcution) la mmoire. a e e La fonction qui permet de rserver de la mmoire est malloc 1 Sa syntaxe est: e e void* malloc(unsigned int taille) La fonction malloc rserve une zone de taille octets en mmoire et renvoie ladresse du dbut de e e e la zone sous forme dun pointeur non-typ (ou NULL si lopration nest pas possible). e e En pratique, on a besoin du type dun pointeur pour pouvoir lutiliser. On souhaite dautre part ne pas avoir a prciser la taille de la mmoire en octets surtout sil sagit de structures. Lusage ` e e consiste donc pour rserver de la mmoire pour une variable dun type donn a: e e e` Dclarer un pointeur du type voulu. e Utiliser la fonction sizeof(type) qui renvoie la taille en octets du type pass en param`tre. e e forcer malloc a renvoyer un pointeur du type dsir. ` e e Par exemple, pour rserver de la mmoire pour un entier, on crira: e e e int* entier; entier=(int*) malloc(sizeof(int)); Ceci est surtout utilis pour des tableaux, par exemple pour un tableau de N complexe (cf. le e paragraphe sur les structures) on crirai: e struct complexe * tabcomp; tabcomp=(struct complexe*) malloc(N*sizeof(struct complexe)); La fonction free() permet de librer la mmoire prcdemment rserve. Sa syntaxe est: e e e e e e void free(void* p)
1. il existe aussi la fonction calloc assez similaire et donc superu...

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Ainsi, dans le second exemple on crirai: e free(tabcomp);

1.4

Pointeurs gnriques e e

En C, les pointeurs comme les autres variables sont typs. Par exemple un pointeur dentiers: e int *p est dirent dun pointeur de rels float *p mme si chacun dentre eux contient une e e e adresse en mmoire. Ceci permet au compilateur de conna le type de la valeur pointe et de la e tre e rcuprer (cest lopration de drfrencement). e e e e ee C ne permet les aectations entre pointeurs que si ceux-ci sont de mme type. Pour crire e e des fonctions indpendantes dun type particulier (par exemple une fonction de permutation) le e mcanisme de typage peut tre contourn en utilisant des pointeurs gnriques. e e e e e Pour crer un pointeur gnrique en C, il faut le dclarer de type void*. e e e e

1.4.1

Copie de zones mmoires e

Lutilisation de pointeurs gnriques ne permet pas dutiliser loprateur de drfrencement * e e e e ee et donc daccder au contenu dune variable. Ceci pose un probl`me si lon veut copier des donnes e e e dune variable dsigne par un pointeur gnrique vers une autre. e e e e La librairie string.h fournit une fonction qui permet de rsoudre ce probl`me: memcpy(): e e Syntaxe: void *memcpy(void *pa, void *pb, unsigned int N) Copie N octets de ladresse pb vers ladresse pa et retourne pa. Lexemple qui suit illustre lutilisation de cette fonction.

1.4.2

Exemple

Si lon nutilise pas des pointeurs gnriques, il faut crire autant de versions de la fonction e e e permutation que de types de variables a permutter: ` Pour des entiers: void permut_int(int *p_a, int *p_b) { int c; c=*p_a; *p_a=*p_b; *p_b=c; } et pour des rels: e void permut_float(float *p_a, float *p_b) { float c; c=*p_a; *p_a=*p_b; *p_b=c; } Que lon utilisera de la mani`re suivante: e int i=2,j=3; float x=3.4,y=6.5; permut_int(&i,&j); permut_float(&x, &y); 5

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Pour pouvoir utiliser la mme fonction quel que soit le type des donnes a manipuler il est e e ` ncessaire de passer en param`tre la taille des donnes a traiter qui dpend de leurs types. e e e ` e La fonction de permutation gnrique peut scrire: e e e void permut(void* p_a, void* p_b, int taille) { void* p_c; p_c=malloc(taille); memcpy(p_c,p_a,taille); /* *p_c=*p_a nest pas autoris */ e memcpy(p_a,p_b,taille); memcpy(p_b,p_c,taille); free(p_c); } Que lon pourra utiliser ainsi: int i=2,j=3; float x=3.4,y=6.5; permut(&i,&j, sizeof(i)); permut(&x, &y, sizeof(x)); On rapelle que la fonction sizeof() renvoie la taille correspondant au type de la variable passe e en param`tre. e Remarquez que cette fonction reste valable pour des structures complexes. Par exemple: struct complexe { double reel; double imag; }; struct complexe cx={1,2}, cy={3,4}; permut(&cx, &cy, sizeof(cx));

1.5

Pointeurs de fonctions

Les pointeurs de fonction sont des pointeurs qui, au lieu de pointer vers des donnes, pointent e vers du code excutable. La dclaration dun pointeur de fonction ressemble a celle dune fonction e e ` sauf que lidenticateur de la fonction est remplac par lidenticateur du pointeur prcd dun e e e e astrisque (*) le tout mis entre parenth`ses. e e Exemple: int (* p_fonction) (int x, int y); dclare un pointeur vers une fonction de type entier ncessitant deux param`tres de type entier. e e e Lintrt est, par exemple, de pouvoir passer en param`tre dune fonction, une autre fonction. e e e Utilisation: int resultat; int calcul(int x, int y) { ... 6

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

} p_fonction=calcul; resultat=p_fonction(3,5); /* Equivalent a resultat=calcul(3,5) */ `

1.5.1

Exemple complet

Recherche du minimum dune fonction monovariable y=f(x) entre 2 bornes (Algorithme plutt o simpliste!): #include <stdio.h> /*-------------------------------------------------------*/ float carre(float x) { return x*x; } /*-------------------------------------------------------*/ float parabole(float x) { return x*x-4*x+2;; } /*-------------------------------------------------------*/ float min_fct(float a, float b, float (* pF) (float x)) { int i; float pas; float vmin; float valeur; pas=(b-a)/100; vmin=pF(a); for (i=1; i<101; i++) { valeur=pF(a+i*pas); if (vmin > valeur) vmin=valeur; } return vmin; } /*-------------------------------------------------------*/ int main() { printf("%f \n",min_fct(-3.0,3.0,carre)); printf("%f \n",min_fct(-3.0,3.0,parabole)); return 0; }

1.6
1.6.1

Compilation spare et classes dallocation de variables e e


Variables locales et globales

Variables locales ou internes Les variables dites locales sont celles qui sont dclares dans un bloc (sparateurs: { et } ). Elles e e e ne sont visibles (donc utilisables) que dans ce bloc. Leur dure de vie va de lexcution du dbut de e e e 7

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

bloc jusqu` la n du bloc (variables volatiles). a Variables globales ou externes Ce sont les variables dclares hors de tout bloc. Elles sont visibles a partir de leur dnition. e e ` e Exemple #include <stdio.h> double x; int N; /* Variables globales */

double f1() { int N; /* variable locale qui masque la variable globale de m^me nom */ e int i; /* autre variable locale */ ... x=...; /* Utilisation de la variable globale x (dconseill) */ e e } int main() { /* dans le main, x et N sont accessibles mais pas i */ }

1.6.2

Dnition et dclaration e e

La dnition dune variable eectue une rservation de mmoire. e e e Ex: int N La dclaration fait rfrence a une dnition. Elle neectue pas de rservation en mmoire, la e ee ` e e e variable doit avoir t dnie par ailleurs. ee e Ex: extern int N

1.6.3

Variables communes

Un programme C, d`s quil devient un peu important, est constitu de plusieurs chiers sources. e e Le partage des variables entre les dirents chiers ncessite certaines prcautions. e e e Une variable globale commune a plusieurs chiers doit tre dnie dans un seul chier et dclare ` e e e e dans tous les chiers qui doivent y avoir acc`s. e Ex: chier1.c: int N; chier2.c: extern int N;

1.6.4

Classe dallocations de variables

Une variable est dnie par sa classe dallocation qui peut tre: extern, auto, static, register. e e Par dfaut (sans prcision) les variables sont de classe auto. Pour dnir une variable dans une autre e e e classe, il faut le prciser en tte de dnition. e e e Le tableau suivant rsume les caractristiques de ces 4 classes. e e Classe auto static register extern Mmoire e pile (volatile) permanente registres permanente 8 Type locale locale locale globale

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Une variable locale peut tre alloue en mmoire permanente si elle est dnie de classe static. e e e e Elle reste visible uniquement dans le bloc o` elle est dnie. u e Exemple: int f() { static int N=0; /* alloue et initialise au premier appel de la fonction*/ e e ... N++; /* compte le nombre dappels de la fonction */ } La dclaration dune fonction poss`de aussi une classe: e e Elle peut tre de classe static. Cel` signie quelle nest visible (appelable) que dans le chier e a o` elle est dnie. u e Elle peut tre de classe extern. Cel` signie quelle est dnie dans un autre chier (seule sa e a e dclaration apparait). e

1.6.5

Fichiers denttes e

Les chiers denttes dextension .h regroupent les dclarations de types, de fonctions et de e e variables exportables cest a dire suceptibles dtre utilises dans plusieurs chiers sources. ` e e En gnral, on cre un chier dentte .h pour chaque chier source .c (except pour le chier e e e e e contenant la fonction main). Le chier source contient les dclarations des fonctions (entte+code) e e et des variables globales. Le chier dentte contient les dnitions des fonctions et variables partae e geables. Exemple: chier: complexe.h struct s_comp { float reel; float imag; } typedef struct s_comp t_comp extern t_comp(J); extern t_comp sommme(t_comp, t_comp); extern t_comp produit(t_comp, t_comp); ... chier: complexe.c #include "complexe.h" t_comp J={0,1}; t_comp somme(t_comp a, t_comp b) { t_comp c; c.reel=a.reel+b.reel; c:imag=a.imag+b.imag; return c; } ... 9

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Utilisation: chier prog.c #include "complexe.h" int main() { t_comp x={3,2},z; z=somme(x,J); ... return 0; } Compilation: gcc -Wall -o prog prog.c complexe.c

10

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Chapitre 2

Algorithmes
2.1 Notion dalgorithme

Un algorithme est une suite de traitements lmentaires eectus sur des donnes en vue dobee e e tenir un rsultat en un nombre nis doprations. e e Traitement lmentaire: traitement pouvant tre eectu par un ordinateur. Notion relative. ee e e Exemple: le calcul de la racine carre dun nombre peut tre considr comme lmentaire en C e e e e ee en utilisant la biblioth`que mathmatique. Il ne lest pas pour un microcontroleur programm en e e e assembleur. Exemple: lalgorithme dEuclide calculant le PGCD de deux entiers: Soit la division euclidienne de a par b, a = bq + r. Lalgorithme dEuclide est bas sur le principe e que les diviseurs communs de a et b sont les mmes que ceux de b et r. En remplaant a par b et b e c par r et en divisant a nouveau, on obtient deux entiers ayant les mmes diviseurs que les entiers a ` e et b dorigine. Finalement, on obtient deux entiers divisibles entre eux (r = 0) dont le plus petit est le PGCD de a et de b.

2.2

Reprsentation des algorithmes e

Un programme est la ralisation dun algorithme. Pour saranchir dun langage de programe mation particulier, direntes techniques de reprsentation sont utilises. e e e

2.2.1

Pseudo langage

Permet de reprsenter formellement un algorithme indpendamment de limplmentation (lane e e gage). Bas sur les instructions disponibles dans la plupart des langages. e Structures lmentaires: ee Entres/Sorties: LIRE, ECRIRE e aectation: X Y instruction conditionnelle: SI condition ALORS instructions SINON instructions FIN SI rptition e e TANT QUE condition FAIRE instructions FIN TANT QUE POUR i=0 A n FAIRE instructions FIN POUR FAIRE instructions TANT QUE condition 11

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Exemple: calculer la factorielle de N (version itrative): e LIRE N F 1 POUR I=1 A N FAIRE F F I FIN POUR ECRIRE F Il nexiste pas de formalisme universel. Chaque auteur a sa syntaxe particuli`re. ` e

2.2.2

Organigramme

Un organigramme permet de reprsenter graphiquement un algorithme. e Exemple pour le calcul de la factorielle:


Lire N

F < 1

I < 1

I<=N Oui F < F*I

Non

I=I+1

Ecrire F

Fig. 2.1 Exemple dorganigramme En pratique cette reprsentation devient vite illisible pour des probl`mes complexes. e e

2.3

Analyse et complexit dun algorithme e

Il existe souvent plusieurs algorithmes permetant de rsoudre un mme probl`me. Exemple: les e e e algorithmes de tri. Le choix du meilleur algorithme implique une analyse de ses performances. En gnral, le crit`re le plus important est celui du temps ncessaire a son excution. Celui ci dpend e e e e ` e e le plus souvent de la quantit de donnes a traiter. Par exemple, le temps ncessiare pour trier un e e ` e ensemble dobjets dpend du nombre dobjets. e Ltude de la complexit dun algorithme consiste essentiellement a valuer la dpendance entre e e `e e le temps dxcution et le volume de donnes 1 . Les rsultats sexpriment de mani`re qualitative: e e e e e On cherche par exemple a savoir si la complexit croit de mani`re linaire ou polynomiale avec le ` e e e volume n de donnes. e
1. On peut aussi sintresser a la quantit de mmoire ncessaire e ` e e e

12

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Par exemple, la recherche dun lment particulier dans un ensemble de n lments non tris ee ee e consiste a examiner chaque lment jusqu` trouver celui que lon cherche. Dans le meilleur cas, ` ee a cela prendra une seule comparaison, dans le pire des cas, il faudra eectuer n comparaisons. En moyenne on aura n/2 comparaisons a eectuer. ` On sintresse en gnral a la complexit dun algorithme: e e e e dans le meilleur cas, en moyenne, dans le pire des cas. On exprime la complexit dun algorithme en ne gardant que le terme variant le plus avec n et e en omettant les termes constants. Par exemple, un algorithme ncessitant 100n 3 + 1000n2 + 5000n + e 10000 instructions lmentaires sera dit de complexit O(n3 ). Un algorithme ne dpendant pas du ee e e volume de donnes sera dit de complexit O(1). e e En gnral un algorithme de complexit O(n log n) sera plus ecace quun algorithme de come e e plexit O(n2 ) mais ceci peut ntre vrai que si n est assez grand. En eet la complexit mesure le e e e comportement asymptotique dun algorithme quand n tend vers linni. Le tableau suivant donne quelques exemples de complexit que lon retrouve couramment. Soit e E un ensemble de n donnes: e Algorithme Accs au 1er lment de E e ee Recherche dichotomique (E tri) e Parcours de E Tri rapide Parcours de E pour chaque lment dun ensemble F de mme dimension ee e Gnration de tous les sous-ensembles de E e e Gnration de toutes les permutations de E e e Complexit e O(1) O(log n) O(n) O(n log n) O(n2 ) O(2n ) O(n!)

Le tableau suivant donne les ordres de grandeurs des direntes complexits en fonction de la e e taille de lensemble de donnes: e Complexit n=1 n=4 e n=16 n=64 n=256 n=4096 O(1) 1 1 1 1 1 1 O(log n) 0 2 4 6 8 12 O(n) 1 4 16 64 256 4096 O(n log n) 0 8 64 384 2048 49152 O(n2 ) 1 16 256 4096 65536 16777216 O(2n ) 2 16 65536 18446744073709551616 O(n!) 1 24 20922789888000 En rsum, la complexit dun algorithme est la courbe de croissance des ressources quil requiert e e e (essentiellement le temps) par rapport au volume des donnes quil traite. e

2.4

Rcursivit e e

Une fonction rcursive est une fonction qui sappelle elle-mme. e e Exemple: calcul de la factorielle dun nombre. Dnition itrative: n! = F (n) = n(n 1)(n 2)...2 1 e e Ce qui donne en C: long int fact(int N) { long int F=1; int i; for (i=1; i<=N; i++) 13

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

F=F*i; return F; } Dnition rcursive: F (n) = nF (n 1), F (0) = 1. Soit en C: e e long int factr(int N) { if (N==0) return 1; else return N*factr(N-1); } Si, en gnral, la version rcursive dun algorithme est plus lgante a crire que sa version e e e ee ` e itrative 2, elle est cependant plus dicile a mettre au point et moins ecace en temps calcul. e ` Pour quun algorithme rcursif fonctionne: e il doit exister un cas terminal que lon est sur de rencontrer. Un mcanisme de pile est par ailleurs ncessaire. Il est naturel en C dans le passage de e e param`tres a une fonction. e `

2.5

Algorithmes de tri

Il sagit dun probl`me classique (et utile) de lalgorithmique. On consid`re un ensemble dlments e e ee possdant une relation dordre total (Exemple: entiers, rels, caract`res). e e e On cherche a ordonner cet ensemble dans lordre croissant (ou dcroissant). ` e

2.5.1

Tri par slection e

Principe Soit un ensemle de n lments indics de 0 a n-1. On suppose que les m premiers lments (0 a ee e ` ee m-1) sont tris. e On cherche la position k du plus petit lment parmi les lments m a n-1. On le permutte avec ee ee ` llment m. Lensemble se trouve donc tri de lindice 0 a lindice m. ee e ` On parcourt ainsi lensemble de llment m=0 a llment n-2. ee ` ee Illustration En gras, les lments dj` tris, en italique, les lments a permutter. ee ea e ee `

18 2 2 2 2 2

10 10 3 3 3 3

3 3 10 9 9 9

25 25 25 25 10 10

9 9 9 10 25 18

2 18 18 18 18 25

2. On peut toujours transformer un algorithme rcursif en algorithme itratif e e

14

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Algorithme Soit a trier un tableau de N lments (entiers), t[0] a t[N-1] ` ee ` POUR m=0 a N-2 FAIRE k p (indice du plus petit lment entre t[m] et t[N-1]) ee SI k dirent de m ALORS permutter t[k] et t[m] FIN SI e FIN POUR Programmation en C Le programme peut se dcomposer en trois fonctions: e une fonction de calcul de lindice du plus petit lment entre t[m] et t[N-1], ee une fonction de permutation, La fonction de tri proprement dite. /* ------------------------ indice du plus grand elment entre m et n-1 */ e int indice_min(int t[], int m, int n) { int i; int imin; imin=m; for (i=m+1; i<n; i++) if (t[i]<t[imin]) imin=i; return imin; } /* ------------------------------------------- permutation de 2 entiers */ void permutte(int *a, int *b) { int c; c=*a; *a=*b; *b=c; } /* -------------------------------------------------- tri par selection */ void tri_selection(int t[], int n) { int m; int p; for (m=0; m<N-1; m++) { p=indice_min(t,m,N); if (p!=m) permutte(&t[p],&t[m]); } } Analyse Cet algorithme ncessite n2 /2 comparaisons et n permutations. Pour un nombre dlments e ee donn, il eectue le mme nombre doprations que les lments soient pratiquements dj` tris ou e e e ee ea e totalement en dsordre. Sa complexit est en O(n2 ). e e 15

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

2.5.2

Tri ` bulle a

Principe Le principe consiste a parcourir les lments de lensemble de i=0 a n-1 en permuttant les ` ee ` lments conscutifs non ordonns. ee e e Llment le plus grand se trouve alors en bonne position. On recommence la procdure pour ee e lensemble de i=0 a n-2 sauf si aucune permutation na t ncessaire a ltape prcdente. Les ` ee e ` e e e lments les plus grands se dplacent ainsi comme des bulles vers la droite du tableau. ee e

2.5.3

Illustration

En italique, les deux lments a comparer, en gras les lments en bonne place. ee ` ee 18 10 10 10 10 10 3 3 3 3 3 3 3 3 3 2 Algorithme k N 1 FAIRE POUR i=0 a J-1 FAIRE SI t[i] > t[i+1] ALORS permutter t[i] et t[i+1] permutation=VRAI FIN SI FIN POUR TANT QUE permutation=VRAI Analyse Dans le pire des cas, le nombre de comparaisons et le nombre de permutations a eectuer sont ` de n2 /2. Dans le meilleur des cas (ensemble dj` tri), le nombre de comparaisons est de n 1 et ea e lalgorithme est donc de complexit linaire. e e 10 18 3 3 3 3 10 10 10 10 10 9 9 9 2 3 3 3 18 18 18 18 18 18 9 9 9 10 2 2 9 9 25 25 25 25 9 9 9 9 18 2 2 2 10 10 10 10 9 9 9 9 25 2 2 2 2 18 18 18 18 18 18 18 2 2 2 2 2 25 25 25 25 25 25 25 25 25 25 25

2.5.4

Tri par insertion

Principe On prend 2 lments et on les met dans lordre. On prend un troisi`me lment quon ins`re ee e ee e dans les 2 lments dj` tris, etc.. ee ea e 16

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Un lment m va tre insr dans lensemble dj` tri des lments 0 a m-1. Ce qui donnera ee e e e ea e ee ` m+1 lments tris (0 a m). ee e ` Linsertion consiste a chercher llment de valeur immdiatement suprieure ou gale a celle de ee e e e ` llment a insrer. Soit k lindice de cet lment, on dcale les lments k a m-1 vers k+1 a m et ee ` e ee e ee ` ` lon place llment a insrer en position k. ee ` e Illustration En gras, llment a insrer dans la partie trie du tableau. ee ` e e 18 10 3 3 3 2 Analyse Dans le pire des cas, le nombre de comparaisons et de n2 /2. Dans le meilleur des cas il est de N . Lalgorithme est de complexit O(N 2 ) mais il est plus ecace que les deux prcdents si le tableau e e e est en partie tri. e 10 18 10 10 9 3 3 3 18 18 10 9 25 25 25 25 18 10 9 9 9 9 25 18 2 2 2 2 2 25

2.6

Algorithmes de recherche dans un ensemble

Un probl`me courant est la recherche dun lment particulier dans un ensemble. La solution la e ee plus simple consiste a parcourir lensemble des lments jusqu` trouver celui que lon cherche. ` ee a Dans le cas ou lensemble de recherche est tri, une solution plus ecace consiste a faire une e ` recherche dichotomique. On peut aussi utiliser des tables de hachage. Le principe consiste a associer a chaque lment ` ` ee de lensemble une cl calcul, cette cl permettant un acc`s direct a un lment. Le calcul de la cl e e e e ` ee e pour llment recherch permet dy accder directement. ee e e On cre en gnral un index contenant linformation sur lequel se fera la recherche. e e e
Index Dupont Albert Durand Marcel Informations Nom: Dupont Prenom adresse tel Nom Albert Prenom adresse tel Nom Durand Prenom adresse tel Nom Marcel Prenom adresse tel

Fig. 2.2 Cration dun index e

17

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

2.6.1

Recherche squentielle e

La recherche squentielle consiste a parcourir chaque lment de lensemble avec celui recherch. e ` ee e En gnral cette recherche se fait sur une information particuli`re de llment ou dans une table e e e ee dindex. Cette mthode fonctionne que lensemble soit tri ou non. e e Dans le meilleur cas, cela prendra une seule comparaison, dans le pire des cas, il faudra eectuer n comparaisons. En moyenne on aura n/2 comparaisons a eectuer. ` La complexit de lalgorithme est donc en O(n). e

2.6.2

Recherche dichotomique

Dans le cas ou lensemble est tri par rapport a lindex sur lequel doit se faire la recherche (par e ` exemple le nom pour un annuaire), un algorithme plus ecace que la simple recherche squentielle e peut tre utilis. e e On compare llment recherch avec celui du milieu de lensemble. Si cest le mme, la recherche ee e e est termin sinon cest quil est plus grand ou plus petit et on recommence en ne gardant que la moiti e e de lensemble. On divise ainsi lensemble de recherche par deux a chaque itration. La complexit ` e e de lalgorithme est donc en O(log n).

2.6.3

Tables de hachage

Le hachage consiste a calculer une cl h(x) (nombre entier) pour chaque lment x. h(x) contient ` e ee lendroit ou lon trouve x dans lensemble. Si lapplication est injective (une cl unique par lment), e ee il sut de calculer la cl de llment recherch et, sil existe, on y acc`de directement. e ee e e Pour des cha nes de caract`res S = s0 s1 s2 ...sl1 , on utilise par exemple la fonction: e h(S) = (s0 B l1 + s1 B l2 + ... + sl2 B + sl1 ) mod N Ou N est la taille de la table de hachage (on choisi un nombre premier) et B une puissance de 2. si est le code ASCII du caract`re dindice i de la cha e ne.
Clef 0 1 2 3 4 5 6 7 Dupont Albert Durand Informations Nom: Dupont Prenom adresse tel Nom Albert Prenom adresse tel Nom Durand Prenom adresse tel Nom Marcel Prenom adresse tel

Marcel

Fig. 2.3 Table de hachage En pratique, lunicit de la cl pour une entre est rarement ralisable. On peut donc avoir e e e e plusieurs lments ayant la mme cl. On parle de collision. Une mthode simple de grer les ee e e e e collisions et de les lister dans une table parall`le. e

18

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Chapitre 3

Structures de donnes e
3.1 Types de donnes abstraits (TDA) e

Un TDA est un ensemble de donnes organis de sorte que les spcications des objets et des e e e oprations sur ces objets (interface) soient spares de la reprsentation interne des objets et de de e e e e la mise en oeuvre des oprations. e Exemple de TDA: le type entier muni des oprations +, , , %, /, >, <, <=, >=, == est un e TDA. Une mise en oeuvre dun TDA est la structure de donnes particuli`re et la dnition des e e e oprations primitives dans un langage particulier. e Les avantages des TDA sont: prise en compte de types complexes. sparation des services et du codage. Lutilisateur dun TDA na pas besoin de conna les e tre dtails du codage. e criture de programmes modulaires. e

3.2

Piles

Une pile est un ensemble de donnes auquelles on acc`de dans lordre inverse ou on les a insres e e e e (Last Input, First Ouput). On ne peut accder quau sommet de la pile. Les oprations (primitives) sur une pile sont les e e suivantes: empiler(lment): rajoute un lment sur la pile. ee ee dpiler: renvoie la valeur de llment au sommet de la pile et le supprime. e ee vide: renvoie VRAI si et seulement si la pile est vide En informatique, une pile sert, par exemple, pour grer les appels et retours de fonctions. Si e au cours de lexcution dune fonction A, la machine doit excuter une fonction B, elle place au e e sommet de la pile dexcution ladresse a laquelle la fonction A a t interrompue puis excute les e ` ee e instructions de la fonction B avant de reprendre lexcution de A a ladresse contenue au sommet de e ` la pile dexcution. Ceci permet dimbriquer des fonctions sans limitation (thorique) de profondeur. e e Les piles sont aussi utilises pour passer des param`tres a une fonction ou pour stocker des e e ` variables locales.

3.2.1

Exemple dutilisation: calcul en notation polonaise inverse (notae tion postx) e

Une formule mathmatique peut tre reprsente par une liste de lex`mes un lex`me pouvant e e e e e e reprsenter: e une valeur 19

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

un oprateur binaire e un oprateur unaire e une parenth`se (ouvrante ou fermante) e Exemple: 4 + 2 16 6

peut tre reprsente par la liste: e e e {(, 4, +, 2, *, sqrt, (, 16, ), ), /, 6} on parle de forme inx, les oprateurs binaires tant placs entre leurs oprandes. e e e e e Il existe aussi une forme prxe ou chaque oprateur prc`de ses oprandes: e e e e e e {/, +, 4, *, 2, sqrt, 16, 6} et une forme postxe ou chaque oprateur vient apr`s son dernier argument: e e e {4, 2, 16, sqrt, *, +, 6, /} Lintrt de cette derni`re forme est quelle ne ncessite pas lutilisation de parenth`ses. e e e e e Lvaluation de la formule postxe peut tre ralise de mani`re simple en utilisant une pile et e e e e e e en suivant les rgles suivantes: e On lit les lex`mes dans lordre de la liste: e si llment de la liste est une valeur, la placer sur la pile. ee si llment de la liste est un oprateur unaire, appliquer loprateur sur le sommet de la pile. ee e e si llment de la liste est un oprateur binaire, appliquer loprateur sur les deux lments de ee e e ee tte de la pile. e Ce qui peut se traduire par lalgorithme suivant utilisant les oprations primitives sur une pile: e pour chaque elment de la liste: e si elment=valeur e empiler(valeur) si elment= oprateur unaire e e operation=lment e e rsultat=opration(depiler) e e empiler(rsultat) e si elment= oprateur binaire e e opration=lment e e e oprande1=dpiler e e oprande2=dpiler e e rsultat=opration(oprande1, oprande2) e e e e empiler(rsultat) e A la n, le sommet de la pile contient le rsultat de la formule. e lment ee 4 2 16 sqrt * + 6 / pile (sommet a droite) ` 4 42 4 2 16 424 48 12 12 6 2

3.2.2

Implmentation des piles e

La mani`re la plus simple dimplmenter une pile consiste a utiliser un tableau. La pile peut e e ` tre caractrise par lindice dans le tableau de son sommet et par une sentinelle permettant de e e e grer les dbordements de la pile. e e 20

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

3.3

Files

Dans une le, les lments sont ajouts en queue et supprims en tte (First Input First Ouput). ee e e e Ils sont donc traits dans lordre darrive. On retrouve les oprations suivantes comme pour les e e e piles: ajouter: rajoute un lment en queue de le. ee supprimer: renvoie la valeur de llment en tte de la le et le supprime. ee e vide: renvoie VRAI si et seulement si la le est vide Les les sont utilises, par exemple, dans les applications pilotes par v`nements. Les v`nements e e e e e e (clavier, souris, ...) sont stocks dans une le par ordre darrive avant dtre traits. e e e e On les utilise aussi pour simuler des les dattente.

3.4
3.4.1

Listes
Gnralits e e e

Une liste est un ensemble ni dlments note L = e1 , e2 , ..., en o` e1 est le premier lment, e2 ee e u ee le deuxi`me, etc... Lorsque n=0 on dit que la liste est vide. e Les listes servent a grer un ensemble de donnes, un peu comme les tableaux. Elles sont ce` e e pendant plus ecaces pour raliser des oprations comme linsertion et la suppression dlments. e e ee Elles utilisent par ailleurs lallocation dynamique de mmoire et peuvent avoir une taille qui varie e pendant lxcution. Lallocation (ou la libration) se fait lment par lment 1 . e e e ee ee Les oprations sur une liste peuvent tre: e e Crer une liste e Supprimer une liste Rechercher un lment particulier ee Insrer un lment (en dbut, en n ou au milieu) e ee e Supprimer un lment particulier ee Permuter deux lments ee Concatner deux listes e ... Les listes peuvent par ailleurs tre: e simplement cha ees n doublement cha ees n circulaires (cha nage simple ou double)

3.4.2

Listes simplement cha ees n

Une liste simplement cha ee est compose dlments distincts lis par un simple pointeur. n e ee e Chaque lment dune liste simplement cha ee est forme de deux parties: ee n e un champ contenant la donne (ou un pointeur vers celle-ci) e un pointeur vers llment suivant de la liste. ee Le premier lment dune liste est sa tte, le dernier sa queue. Le pointeur du dernier lment ee e ee est initialis a une valeur sentinelle, par exemple la valeur NULL en C. e` Pour accder a un lment dune liste simplement cha ee, on part de la tte et on passe dun e ` ee n e lment a lautre a laide du pointeur suivant associ a chaque lment. ee ` ` e` ee En pratique, les lments tant cres par allocation dynamique, ne sont pas contigus en mmoire ee e e e contrairement a un tableau. La suppression dun lment sans prcaution ne permet plus daccder ` ee e e
1. Un tableau peut aussi tre dni dynamiquement mais pour modier sa taille, il faut en crer un nouveau, e e e transfrer les donnes puis supprimer lancien. e e

21

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

tete (NULL)

queue donnee: pointeur:

Fig. 3.1 Liste simplement chane e aux lments suivants. Dautre part, une liste simplement chaine ne peut tre parcourue que dans ee e e un sens (de la tte vers la queue). e Exemple dimplmentation sous forme dune structure en C: e struct s_element { int donnee; struct s_element* suivant; }; typedef struct s_element t_element;

3.4.3

Listes doublement cha ees n

Les listes doublement cha ees sont constitues dlments comportant trois champs: n e ee un champ contenant la donne (ou un pointeur vers celle-ci) e un pointeur vers llment suivant de la liste. ee un pointeur vers llment prcdent de la liste. ee e e Elles peuvent donc tre parcourues dans les deux sens. e
tete (NULL)

donnee:

pointeur:

Fig. 3.2 Liste doublement chane e

3.4.4

Listes circulaires

Une liste circulaire peut tre simplement ou doublement cha ee. Sa particularit est de ne pas e n e comporter de queue. Le dernier lment de la liste pointe vers le premier. Un lment poss`de donc ee ee e toujours un suivant.
tete

donnee:

pointeur:

Fig. 3.3 Liste circulaire simplement chane e

22

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

3.4.5

Oprations sur une liste e

On ne dcrira dans ce paragraphe que quelques oprations sur les listes simplement cha ees. e e n Insertion dun lment ee Linsertion dun lment dans une liste peut se faire: ee en tte de liste e en queue de liste nimporte ou (` une position x par un pointeur dit courant) a e Lexemple choisi est celui de linsertion nimporte o` (apr`s llment rfrenc par le pointeur u e ee ee e courant):

Avant insertion:
tete

queue

(NULL) courant

nouveau

Apres insertion:
tete

queue

(NULL) courant

nouveau

Fig. 3.4 Insertion Les oprations a eectuer sont (dans lordre!): e ` allouer de la mmoire pour le nouvel lment e ee copier les donnes e faire pointer le nouvel lment vers llment suivant de celui point par courant (vers NULL ee ee e sil ny a pas de suivant) faire pointer llment point par courant vers le nouvel lment ee e ee Le cas ou la liste est vide (tete gal a NULL) doit tre trait a part. e ` e e` Exemple dimplmentation de la fonction dinsertion: e void insertion(t_element** tete, t_element* courant, int data) { t_element* nouveau; nouveau=(t_element*) malloc(sizeof(t_element)); nouveau->donnee=data; if (courant!=NULL) { nouveau->suivant=courant->suivant; courant->suivant=nouveau; 23

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

} else /* insertion en tete ou liste vide */ { nouveau->suivant=*tete; *tete=nouveau; } } Suppression dun lment ee
Avant suppression:
tete (NULL) precedent courant

Apres suppression:
tete (NULL) precedent courant

Fig. 3.5 Suppression Dans le cas dun liste simplement cha ee, la fonction de suppression demande un peu de rexion n e pour tre implment. e e e Par exemple, une fonction permettant de supprimer llment point par courant pourrait avoir ee e cette interface: void suppression(t_element** tete, t_element* courant) Le passage du pointeur de tte par adresse est ncessaire pour pouvoir le modier si la supprese e sion rend la liste vide ou si llment a supprimer tait le premier de la liste. ee ` e On doit dabord distinguer sil sagit du 1er lment de la liste ou pas: ee if (courant!=*tete) /* pas le premier element */ Dans ce cas il faut chercher le prdcesseur de courant. La liste tant simplement cha ee, on na e e e n pas dautre solution que de faire un parcours depuis la tte jusqu` trouver le prcdent de courant. e a e e precedent=*tete; while (precedent->suivant!=courant) precedent=precedent->suivant; On peut alors rcuprer le lien contenu dans le champ suivant de llment a supprimer: e e ee ` precedent->suivant=courant->suivant; Dans le cas ou cest le premier lment que lon supprime, on modie simplement le pointeur de ee tte: e else /* suppression du 1er element */ *tete=courant->suivant; Enn, dans tous les cas on lib`re la mmoire: e e free(courant);

24

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Noter que dans cette implmentation, le pointeur courant devient un pointeur pendant au retour e de la fonction. Ce probl`me doit tre trait au niveau de lappel de la fonction ou en modiant un e e e peu limplmentation de la fonction (prfrable!). e ee

3.4.6

Exemple dutilisation

Une fois que les primitives de manipulation de la liste ont t implmentes, lutilisation est ee e e relativement simple. Lexemple suivant utilise les deux primitives vues prcdemment (insertion et suppression). e e int main() { t_element* tete=NULL; t_element* courant=NULL; /* insertion dun premier element: liste: 1 */ insertion(&tete,courant,1); /* deuxieme apres le premier: liste: 1 2 courant=tete; insertion(&tete,courant,2); /* courant pointe sur 2. liste: 1 2 3 */ courant=courant->suivant; insertion(&tete,courant,3); /* courant pointe sur 2. liste: 1 2 4 3 */ insertion(&tete,courant,4); /* insertion en tete. liste: 5 1 2 4 3 */ insertion(&tete,NULL,5); /* suppression de lelement 1. liste: 5 2 4 3 */ courant=tete->suivant; suppression(&tete,courant); /* suppression de la tete. liste: 2 4 3 */ courant=tete; suppression(&tete,courant); return 0; } */

25

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Chapitre 4

Arbres binaires
4.1 Introduction

Un arbre est une structure compose de noeuds et de feuilles (noeuds terminaux) relis par des e e branches. On le reprsente gnralement en mettant la racine en haut et les feuilles en bas (contraie e e rement a un arbre rel). ` e

Racine

Feuilles

Fig. 4.1 Exemple darbre

Le noeud A est la racine de larbre. Les noeuds E, I, J, M, L et H sont des feuilles. Les noeuds B, C, D, F, G et K sont des noeuds intermdiaires. e Si une branche relie un noeud ni a un noeud nj situ plus bas, on dit que ni est un anctre ` e e de nj . Dans un arbre, un noeud na quun seul p`re (anctre direct). e e Un noeud peut contenir une ou plusieurs valeurs. La hauteur (ou profondeur) dun noeud est la longueur du chemin qui le lie a la racine. `

4.2

Arbres binaires

Un arbre binaire est un arbre tel que les noeuds ont au plus deux ls (gauche et droit).

27

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

Fig. 4.2 Exemple darbre binaire

4.3

Arbres binaires de recherche

Un arbre binaire de recherche est un arbre binaire qui poss`de la proprit fondamentale suivante: e ee tous les noeuds du sous-arbre de gauche dun noeud de larbre ont une valeur infrieure ou e gale a la sienne. e ` tous les noeuds du sous-arbre de droite dun noeud de larbre ont une valeur suprieure ou e gale a la sienne. e ` Exemple:
10

13

11

15

Fig. 4.3 Arbre binaire de recherche

4.3.1

Recherche dans larbre

Un arbre binaire de recherche est fait pour faciliter la recherche dinformations. La recherche dun noeud particulier de larbre peut tre dnie simplement de mani`re rcursive: e e e e Soit un sous-arbre de racine ni , si la valeur recherche est celle de la racine ni , alors la recherche est termine. On a trouv le e e ` e noeud recherch. e sinon, si ni est une feuille (pas de ls) alors la recherche est infructueuse et lalgorithme se termine. si la valeur recherche est plus grande que celle de la racine alors on explore le sous-arbre e de droite cest a dire que lon remplace ni par son noeud ls de droite et que lon relance la ` procdure de recherche a partir de cette nouvelle racine. e ` 28

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

de la mme mani`re, si la valeur recherche est plus petite que la valeur de n i , on remplace e e e ni par son noeud ls de gauche avant de relancer la procdure.. e Si larbre est quilibr chaque itration divise par 2 le nombre de noeuds candidats. La complexit e e e e est donc en O(log2 n) si n est le nombre de noeuds de larbre.

4.3.2

Ajout dun lment ee

Pour conserver les proprits dun arbre binaire de recherche ncessite de, lajout dun nouvel ee e lment ne peut pas se faire nimporte comment. ee Lalgorithme rcursif dajout dun lment peut sexprimer ainsi: e ee soit x la valeur de llment a insrer. ee ` e soit v la valeur du noeud racine ni dun sous-arbre. si ni nexiste pas, le crer avec la valeur x. n. e sinon si x est plus grand que v, remplacer ni par son ls droit. recommencer lalgorithme a partir de la nouvelle racine. ` sinon remplacer ni par son ls gauche. recommencer lalgorithme a partir de la nouvelle racine. `

5<6

3 4

5>3

9 8 12 10

1 0

5>4

Fig. 4.4 Ajout de 5 dans larbre

4.3.3

Implmentation e

En langage C, un noeud dun arbre binaire peut tre reprsent par une structure contenant un e e e champ donne et deux pointeurs vers les noeuds ls: e struct s_arbre { int valeur; struct s_arbre * gauche; struct s_arbre * droit; }; typedef struct s_arbre t_arbre; La fonction dinsertion qui permet dajouter un lment dans larbre et donc de le crer de ee e mani`re a ce quil respecte les proprits dun arbre binaire de recherche peut scrire ainsi: e ` ee e void insertion(t_arbre ** noeud, int v) 29

L3 IUP AISEM/ICM

Algorithmique et langage C

J.M. ENJALBERT

{ if (*noeud==NULL) /* si le noeud nexiste pas, on le cre */ e { *noeud=(t_arbre*) malloc(sizeof(t_arbre)); (*noeud)->valeur=v; (*noeud)->gauche=NULL; (*noeud)->droit=NULL; } else { if (v>(*noeud)->valeur) insertion(&(*noeud)->droit,v); /* aller a droite */ else insertion(&(*noeud)->gauche,v); /* aller a gauche */ } } On peut noter par ailleurs que larbre qui sera construit dpendra de lordre dans lequel seront e insres les direntes valeurs. En particulier, si les valeurs sont insres dans un ordre croissnt on e e e e e obtiendra un arbre compl`tement dsquilibr, chaque noeud nayant quun ls droit (gauche si les e e e e valeurs sont dans un ordre dcroissant). e

30

Vous aimerez peut-être aussi