LA RÉCURSIVITÉ QU’EST-CE QUE LA RÉCURSIVITÉ ? Un sous-programme(fonction ou procédure) est dit récursifs’ il s’appelle lui-même directement ou indirectement. Exemple La fonction suivante calcule la factorielle n! D’un nombre n. On se base sur la relation de récurrence n! = (n − 1)! ∗n. en c Fonction FactorielleRécursive(n: entier) Début Si (n=0) alors return 1; sinon return n*FactorielleRecursive(n-1) finsi fin int FactorielleRecursive(int n) {if (n <= 0) return 1; else return n*FactorielleRecursive(n-1); /* appel récursif */ } L’appel d’une fonction à l’intérieur d’elle-même est nommé appel récursif. Un appel récursif doit obligatoirement être dans une instruction conditionnelle (sinon la récursivité est sans fin). Remarque 1. tout programme récursif peut implémenter manière itérative (en utilisant les boucles). 2. les programmes récursifs sont plus simplesàécrire et à lire. 3. les programme récursive sont inefficaces comparativement au programme itérative. 1 STRUCTURE DE DONNEES DYNAMIQUES Motivations (problématique) : supposons qu’on a souhaité gérer une liste d’objets. la solution traditionnelle consiste à les représenter sous forme d’un tableau .donc on va avoir les déclarations suivantes : Type objet record début …… fin var t tableau[ n ] : objet ; on doit déclarer la taille n comme une constante comme exemple : Soit T l’ensemble des étudiants d’un groupe donnée l’ensemble des éléments du tableau T peuvent être ordonnées ; cette solution présente plusieurs problèmes 1. problème de taille . 2. insertion d’un élément dans le cas ou T est triée . 3. suppression d’un élément( des trous dans T ). solution la solution à ces problèmes consiste à ne pas utiliser des variables statiques ( comme les tableaux ) et à utiliser des variables dont la taille change au cours de l’exécution du programme. principe : réservation de l’espace mémoire si on a besoin et libération de l’espace si on n’a pas besoin. 2) pointeur :le concept de pointeur est essentiel pour la gestion dynamique d’un ensemble d’objet. un pointeur est un variable dont les valeurs admissibles sont des adresses mémoires . donc , on a besoin d’un nouveau type qui correspond au pointeur . il n’ya pas dans les langages de programmation un nouveau type pour déclarer un pointeur . maisils nous donnent un autre moyen pour les déclarer exemple : soit x ,y deux variables entiers ( int x ,y ; ), supposons qu’on va définir des variables px , py pour pointer sur x et y. var x , y : entier ; px , py : ↑entier ; en c int x,y ; int *px, *py ; int t[ 10 ] ; // ( t est un pointeur reçoit la première adresse du tableau « *t le contenu de 1er adresse équivalent t[0] ») 2 on peut écrire px = &x ; py = &y ; x = * py ( xreçoit le contenu « * » de l’adresse trouver dans py « équivalente x = y » ). px = py ; *px = ( *px) +1 ; ( équivalente x = x+1 ) px= t ; *px = ( *px +1) ; ( équivalente t[0] = t[1] ou *t = ( *t +1) ) ; LISTES CHAÎNÉES Une liste chaînée est un ensemble des objets liés entre eux par des pointeurs. Chaque objet est une structure contenant les champs suivants : • une ou plusieurs données comme dans n’importe quelle structure ; • un pointeur suivant sur la cellule suivante. On accède à la liste par un pointeur L sur le premier élément, puis en parcourant la liste d’un élément à l’autre en suivant les pointeurs suivant. Le dernier pointeur suivant vaut NULL, ce qui indique la fin de la liste. L elem1 elem2 …. elem n NULL DÉCLARER UNE LISTE CHAÎNÉE Pour créer une liste chaînée, il faut déclarer une nouvelle structure de données : la structure qui représentera un élément. /* exemple : les données dans les éléments sont des nombres réelles */ Typedef struct elem { Floatdonnee; elem *suivant; /* pointeur sur la structure suivante de type elem */ }elem; La structure elem contient un pointeur suivantsurelem. On déclare ensuite le pointeur sommet qui donne l’adresse du premier élément comme suit elem*sommet ; /* déclaration d’une liste */ la liste est vide suit a l’exécution de l’instruction sommet=NULL ; 3 1. Insertion d’un élément les étapesnécessaires pour ajouter un élément la liste sont 1. réserver un espace mémoire dont l’adresse est stocké dans un pointeur p. 2. affectation des données vers les champs données 3. insertion effective de l’élément dans la liste. opérations 1 : cette opération se réalise par l’appel vers une fonction de compilateur (fonction système) new ( p ) ( réserver un espace mémoire et mettre son adresse dans p) p doit êtredéclaré avant utiliser comme suit Var p :↑elem ; en langage c on utilise la fonction malloc comme suit p=(elem *)malloc(sizeof(elem)) ; (réserver un espace mémoire de taille correspond au type elem ) opérations 2 : des affectations classiques opérations 3 : dans le cas d’insertion au début p↑.suivant ← sommet ; sommet ← p ; 2. suppression d’un élément opérationsnécessaires 1. trouver l’élément p à supprimé en parcourant la liste a partir du sommet( recherche dans la liste). 2. faire sortir l’élément depuis la liste en manipulant le contenu des pointeurs 3. libération de l’espace mémoire. Operations 1 : x←sommet ; prec←sommet ; Tantque( x ≠ p et x ≠ NULL) prec←x ; x←x↑.suivant ; fin-tantque si (x=p) alors l’élément existe ; sinon l’élément n’existe pas ; finsi Operations 2 : prec↑.suivant ←x↑.suivant ; Operations 3 : free( p ) ; 4 Remarque : selon l’opération insérer un élément dans une liste chainée, le nouvel élémentinséré devient toujours le premier ; et si l’élément a supprimé devient toujours le premier ; ce type de liste suit une stratégie dite FILO ( First In Last Out « premier arrivée dernier à servir »)ou LIFO ( Last In First Out « dernier arrivée premier à servir »). cette stratégie est utilisée pour gérer une structure particulière appelée « PILE» ( STUCK ). LES PILES Une pile est une structure (dynamique) qui suit la stratégie FILO ( First In Last Out ) opérations sur les piles :on a 4 opérations Empiler (Push) : insérer un élémentE dans une pile P Empiler( E, P ) ; Depiler (POP) : faire sortir un élément depuis une pile P Depiler( P ) ; Sommet (TOP) : retourne la valeur stockée dans le sommet de la pile P Sommet( p) ; Est_vide (Is-Empty) : retourne vrai (1) si la pile P est vide, faux (0) sinon Est_vide ( p ) ; En c Codes operations : Type elem record { Float donnee; elem*suivant; }elem; 1. Fonction est_vide( L :↑elem) : booléen Debut Si (L=NULL) alors Return( vrai) ; Sinon Return( faux) ; finsi fin 2. Fonction Sommet ( L :↑elem) : réel Debut Return( L↑.donnee) ; Fin Typedefstructelem { Float donnee; elem *suivant; }elem; int est_vide(elem *L) { if (L==NULL) Return 1 ; Else Return 0 ; } 2. Float Sommet( elem *L) { Return ( L→donnee ) ; } 3. 5 Procedure Empiler (varL :↑elem , inf : reel ) Vare : ↑elem ; Debut Reserver( e ) ; e↑.donnee←inf ; e↑.suivant← L ; L=e ; Fin 3. Void Empiler (elem **L ,floatinf) { elem *e ; e=(elem *)malloc(sizeof(elem)) ; e→donnee=inf ; e→suivant= *L ; *L= e ; 4. Procedure Depiler (L :↑elem) Vare : ↑elem ; Debut e←L; L← L↑.suivant; Libérer (e) ; Fin } 4. Void Depiler (elem **L ) { elem *e ; e=*L ; *L =*L →suivant; Free(e) ; } RQ : L’aspect contrôle a été laissé au programme appelant . LES FILES Une file est une structures de données dans laquelle on peut ajouter et supprimer des éléments suivant la règle du premier arrivé premier sorti, ou encore FIFO (First In First Out) Le nom de file vient d’une analogie avec une file d’attente à un guichet, dans laquelle le premier arrivé sera le premier servi. Les usagers arrivent en queue de file, et sortent de la file à sa tête. Tète elem1 elem2 …. elem n NULL Queue .opérationsapplicablesur les Files :on a 4 opérations Enfiler: insérer un élément E dans une File F Enfiler( E, F ) ; Défiler: faire sortir un élément depuis une File FDéfiler( F ) ; Premier : retourne la valeur stockée dans le premier élémentde la File FPremier ( F) ; Dernier : retourne la valeur stockée dans le premier élément de la File F Dernier ( F) ; Est_vide: retourne vrai (1) si la file F est vide , faux (0) sinon Est_vide ( F ) ; 6 Codedes opérations : Type elem record debut var donnee :réel; suivant :↑elem ; fin Type file record debut var tete:↑elem ; queue: :↑elem ; fin 1. Fonction est_vide( L : file ) : booléen Debut Si (L.tete=NULL) alors Return( vrai) ; Sinon Return( faux) ; finsi fin 2. Procedure Enfiler (varL :file , inf : reel ) Vare : ↑elem ; Debut Reserver( e ) ; e↑.donnee←inf ; e↑.suivant←L.tete ; si(est_vide (L)=vrai) alors L.tete←e ; L.queue← e ; sinon L↑.tete← e ; finsi Fin 3. Procedure Defiler (varL : file) Debut L.tete← L.tete ↑.suivant; si(est_vide (L)=vrai) alors L.queue ← L. tete ; Finsi Fin En c Typedefstructelem { Float donnee; elem *suivant; }elem; Typedefstruct file { elem *tete; elem *queue; }elem; int est_vide(file L) { if (L.tete==NULL) Return 1 ; Else Return 0 ; } 2. Void Enfiler (file *L, float inf) { elem *e ; e=(elem *)malloc(sizeof(elem)) ; e→donnee = inf ; e→suivant= *L.tete ; if(est_vide (*L)==1) {*L.tete= e ; *L.queue= e ; } Else *L.tete= e ; 3. } VoidDefiler (file *L ) { *L.tete= *L.tete →suivant; if(est_vide (*L)==1) { *L.queue= NULL ; } } 7 LES ARBRES Les Arbres sont des structures de donneeshierarchiques un arbre est un ensemble de nœuds inter connectés par des arcs. cettedefinition concerne ce qu’on appelle « Graphes » définition un graphe G est un ensemble de sommets reliés par des arcs G = ( V , E )ou : V : l’ensemble des sommets (nœuds) = { v1 , v2, v3 ,…, vn } E : { (v1 , v2) , (v1 , v5) ,(v2 , v4 ) ,(v 3 , v 2) ,……,(vi,vj) } chaqueelement de E est un couple (vi, vj) représente une connexion depuis vi vers vj définition un arbre est un graphe avec la particularité suivante : nœud « racine » : a partir du quel on peut accéder aux autres nœuds qui sont classés en sous arbres disjoints . notation : un nœud est soit : 1. racine 2. feuille 3. interne pour un nœud quelconque V , on trouve le père de V : le nœud de niveau inferieur a partir du quel on accede a V. le fils de V : le nœud de niveau suivant accessible à partir de V. pour programmer ce genre de structures de données , on doit en premier lieu procéderà la déclaration 8