La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

1 Algorithmique et structures de données en C É. Delozanne, L2-S4-prog4, Paris 5

Présentations similaires


Présentation au sujet: "1 Algorithmique et structures de données en C É. Delozanne, L2-S4-prog4, Paris 5"— Transcription de la présentation:

1 1 Algorithmique et structures de données en C É. Delozanne, L2-S4-prog4, Paris 5 Les arbres (3) : Parcours Cours 6

2 2 Parcourir un arbre ?  parcours : examiner les nœuds d’un arbre pour effectuer un traitement  2 types de parcours classiques sur les arbres binaires en profondeur à main gauche (récursif par nature) en largeur (itératif par nature)

3 3 Plan du cours :  parcours en profondeur à main gauche algorithme récursif général –cas particuliers (parcours préfixe, infixe, postfixe) algorithme itératif général : utilise une pile –application : calcul de la hauteur d'un arbre –simplification dans le cas d'un parcours préfixe  parcours en largeur (par niveaux, hiérarchique) : utilise une file  récursivité et itération Parcours d'arbres binaires : récursifs/itératifs

4 4 Objectifs du cours (et TD)  Mise en œuvre en C d’algorithmes (un peu) complexes  Culture informatique de base sur les algorithmes récursifs et itératifs et sur la compilation  Vue abstraite sur les parcours d’arbres pour savoir les écrire plus facilement  Compétence à acquérir : Savoir écrire rapidement et sans erreur les algorithmes récursifs classiques de parcours d’arbres binaires –Afficher, lire, construire, hauteur, taille, libérer la mémoire, tests etc. Savoir programmer un parcours en largeur

5 5 Parcours en profondeur à main gauche  chemin qui descend toujours le plus à gauche possible  chaque nœud est rencontré 3 fois 1.à la descente avant la visite du sous-arbre gauche –on applique au nœud le traitement 1 2.Après la visite du sous-arbre gauche et avant de descendre dans le sous-arbre droit –on applique au nœud le traitement 2 3.(et dernière fois) quand les deux sous-arbres ont été parcourus, en remontant à droite –on applique au nœud le traitement 3  si l'arbre est vide on lui applique un traitement appelé terminaison

6 6 Parcours récursif en profondeur à main gauche Algorithme Parcours (A)  si A est vide alors terminaison(A) sinon 1. traitement1 (A) 2. Parcours(sous-arbreGauche(A) 3. traitement2 (A) 4. Parcours(sous-arbreDroit(A) 5. traitement3 (A) Exemple : void ArbinTracer(ARBIN A){ if (ArbinVide(A)) /* terminaison */ printf("() "); else { ElementAfficher(ArbinEtiquette(A)); /* traitement 1 */ ArbinTracer(ArbinGauche(A)) ; ElementAfficher(ArbinEtiquette(A)); /* traitement 2 */ ArbinTracer(ArbinDroit(A)) ; ElementAfficher(ArbinEtiquette(A)); /* traitement 3 */ }

7 7 Cas particuliers Lorsque le noeud est traité une seule fois  Parcours préfixe (Racine Gauche Droit) le nœud racine est traité au premier passage avant le parcours des sous-arbres  Parcours infixe ou symétrique (Gauche Racine Droit) le nœud racine est traité au second passage –après le parcours du sous-arbre gauche –et avant le parcours du sous-arbre droit  Parcours postfixe (Gauche Droit Racine ) le nœud racine est traité en dernier après le parcours des sous-arbres

8 8 Parcours préfixe (R G D)  le nœud racine est traité au premier passage avant le parcours des sous-arbres  ParcoursPréfixe(A) si A est vide –alors terminaison(A) –sinon s traitement (A) s ParcoursPréfixe(sous-arbreGauche de A) s ParcoursPréfixe(sous-arbreDroit de A)

9 9 Exemple : RGD  Afficher les étiquettes d'un arbre (ordre préfixe) terminaison : afficher arbre vide () - juste pour voir traitement 1 : afficher l'étiquette  void ArbinAfficherPref(ARBIN A){ if (ArbinVide(A)) printf("() "); /* terminaison */ else { ElementAfficher(ArbinEtiquette(A)); /* traitement 1 */ ArbinAfficherPref(ArbinGauche(A)) ; ArbinAfficherPref(ArbinDroit(A)) ; } }

10 10 Parcours infixe ou symétrique (G R D)  le nœud racine est traité au second passage après le parcours du sous-arbre gauche et avant le parcours du sous-arbre droit  ParcoursInfixe(A) si A est vide –alors terminaison(A) –sinon s ParcoursInfixe(sous-arbreGauche de A) s traitement (A) s ParcoursInfixe(sous-arbreDroit de A)

11 11 Exemple : GRD  Afficher les étiquettes d'un arbre (ordre infixe) terminaison : afficher arbre vide () traitement 2 : afficher l'étiquette  void ArbinAfficherInf(ARBIN A){ if (ArbinVide(A)) printf("() "); /* terminaison */ else { ArbinAfficherInf(ArbinGauche(A)) ; ElementAfficher(ArbinEtiquette(A)); /* traitement 2 */ ArbinAfficherInf(ArbinDroit(A)) ; } }

12 12 Parcours postfixe (G D R)  le nœud racine est traité au troisième passage après le parcours des sous-arbres gauche et droit  ParcoursPostfixe(A) si A est vide –alors terminaison(A) –sinon s ParcoursPostfixe(sous-arbreGauche de A) s ParcoursPostfixe(sous-arbreDroit de A) s traitement (A)

13 13 Exemples : GDR  Afficher les étiquettes d'un arbre (ordre postfixe) terminaison : afficher arbre vide traitement 3 : afficher l'étiquette  code C void ArbinAfficherPost(ARBIN A){ if (ArbinVide(A)) printf("() "); /* terminaison */ else { ArbinAfficherPost(ArbinGauche(A)) ; ArbinAfficherPost(ArbinDroit(A)) ; ElementAfficher(ArbinEtiquette(A)); /* traitement 3 */ } }

14 14 "Dérécursiver"  dérécursiver = transformer un algorithme récursif en algorithme itératif  pour des raisons d'efficacité (économie de temps et de mémoire) « on » peut être amené à "dérécursiver" certains algorithmes « on » : le plus souvent les compilateurs  méthodes générales pour supprimer : un appel récursif terminal : –utilise une boucle tant que un appel récursif non terminal : –utilise une pile

15 15 Parcours itératif en profondeur à main gauche idée : une pile mémorisant le nœud courant et la direction future 1. descente (à gauche du nœud, 1ier passage) effectuer le traitement 1 sur la racine empiler le nœud et la direction future (descendre à dr., 2ième passage) descendre à gauche sur le sous-arbre gauche 2. remontée gauche (2ième passage) effectuer le traitement 2 sur la racine empiler le nœud et la direction future (remonter à droite, 3ième passage) descendre à gauche sur le sous-arbre droit 3. remontée droite (3ième passage) effectuer le traitement 3 sur la racine dépiler le nœud et le sens de la visite sur ce nœud

16 16 Parcours itératif en profondeur à main gauche  A = l'arbre à parcourir  créer une pile vide P, direction = descente gauche ; fini = A non vide  tant que (pas fini) Si A est vide –alors s terminaison s Si P est vide alors fini sinon (A et direction) = dépiler si (pas fini) selon direction s direction = descente gauche – traitement 1, empiler (A, desc. dr), –A = ss-arbGauche (A) (desc. à g. sur le sous-arbre gauche) s direction = descente droite – traitement 2, empiler (A, montée. dr), –A = ss-arbDroit (A), direction = descente gauche (descendre à gauche sur le sous-arbre droit) s direction = montée droite – traitement 3, –Si P est vide alors fini sinon (A et direction) = dépiler  détruire la pile P

17 17 Exemple : calcul de la hauteur d'un arbre  hauteur(A) (algorithme récursif) si A est vide retourner -1 sinon – hg = Hauteur(sous-arbreGauche(A) – hd = Hauteur(sous-arbreDroit(A) – si hg > hd s retourner hg +1 s sinon retourner hd + 1

18 18 Calcul itératif de la hauteur d'un arbre binaire  A arbre à parcourir, h = -1, max = -1,  créer une pile vide P, direction = descente gauche  répéter jusqu'à Pile vide et direction = montée droite si A est vide alors –direction = montée droite –si h > max alors max = h si ( Pile non vide ou direction ≠ montée droite) alors selon direction t direction = descente gauche s h ++, empiler (A, desc. dr), s A = ss-arbGauche (A) t direction = descente droite s h++, empiler (A, montée. dr), s A = ss-arbDroit (A), direction = descente gauche t direction = montée droite s h--, dépiler le nœud A et la direction  détruire P et retourner max

19 19 Codage en C  idée géniale : utiliser le TDA PILE (cours 3) et le TDA ARBRE BINAIRE (cours 5)  problème le TDA ARBRE BINAIRE utilise un TDA ELEMENT incarné par des entiers (ou des caractères) le TDA PILE utilise lui aussi un TDA ELEMENT mais incarné par des couples (arbres, position)  le souk ! un même identificateur (ELEMENT) désigne deux types différents  solution en C : bricolo en C++ : les template (polymorphisme paramétrique) en Smalltalk, Java : polymorphisme d’héritage

20 20 Simplifications de l'algorithme général exemple : Parcours préfixe itératif (à la Sedgewick=  A arbre à parcourir  créer une Pile vide P  si l'arbre A est non vide empiler A  tant que P est non vide répéter dépiler dans A traiter (A) si le sous-arbre droit est non vide, l'empiler si le sous-arbre gauche est non vide, l'empiler  détruire (P)

21 21 Plan du cours : parcours en profondeur à main gauche algorithme récursif général cas particuliers (parcours préfixe, infixe, postfixe) algorithme itératif général : utilise une pile application : calcul de la hauteur d'un arbre simplification dans le cas d'un parcours préfixe  parcours en largeur (par niveaux, hiérarchique) : utilise une file  récursivité et itération Parcours d'arbres binaires : récursifs/itératifs

22 22 Parcours en largeur (hiérarchique, par niveau)  stratégie pas du tout récursive  traitement des nœuds par niveau : traiter les frères avant les fils  dans la représentation graphique : 1. de gauche à droite 2. de haut vers le bas  utilisation d'une file on traite un nœud on fait entrer dans la file –d’abord son fils gauche –puis son fils droit

23 23 Algorithme ParcoursEnLargeur (A)  créer une file vide F  si A est non vide alors entrer A dans F tant que F non vide 1.A = sortir(F) 2.traiter (A) 3.si ss-arbGauche(A) non vide l'entrer dans F 4.si ss-arbDroit(A) non vide l'entrer dans F  FinSi  détruire F

24 24 Affichage en largeur void ArbinAfficherLargeur(ARBIN A){ FFILE F = FileCreer(20) ; ELTSPCL elt ; if ( ! ArbinVide(A) ) { elt = EltSpclInit(A,1) ; FileEntrer(elt, F) ; while ( ! FileVide (F) ) { A = EltSpclArbre(FileSortir(F)) ; ElementAfficher(ArbinEtiquette(A)); if( ! ArbinVide(ArbinGauche(A)) ) { elt = EltSpclInit(ArbinGauche(A),1) ; FileEntrer(elt, F); } if( ! ArbinVide(ArbinDroit(A)) ) { elt = EltSpclInit(ArbinDroit(A),1);FileEntrer(elt, F) ; } } } FileDetruire(F) ;}

25 25 Plan du cours : parcours en profondeur à main gauche algorithme récursif général cas particuliers (parcours préfixe, infixe, postfixe) algorithme itératif général : utilise une pile application : calcul de la hauteur d'un arbre simplification dans le cas d'un parcours préfixe parcours en largeur (par niveaux, hiérarchique) : utilise une file  récursivité et itération Parcours d'arbres binaires : récursifs/itératifs

26 26 Y'avait longtemps...  factorielle version récursive long factorielle (int n) { if (n < = 0) return 1 ; else return n * factorielle (n - 1) ; }  factorielle version itérative long factorielle (int n) { int r = 1 ; while ( n > 1) { r = r * n ; n -- ; } return r ; }

27 27 Et sa copine...fibonacci  fibonacci version récursive long fibonacci (int n) { if (n < = 1) return 1 ; else return fibonacci (n - 1) + fibonacci (n - 2) ; }  fibonacci version itérative long fibonacci (int n) { int u, v ; u = v = 1 ; for (i = 3 ; i <= n ; i++) { u = u + v ; v = u - v ; } return u ; }

28 28 Récursif versus itératif  sur ces 2 exemples triviaux la solution itérative est meilleure  certains compilateurs astucieux remplacent l'appel récursif terminal par une boucle tant que un appel non terminal par un algorithme itératif utilisant une pile  certains algorithmes sont « naturellement » récursifs 1) algorithmes récursifs de type diviser pour résoudre –2 appels récursifs traitant chacun en gros la moitié des données sans calcul redondant 2) algorithmes récursifs de type combiner pour résoudre –commencer par résoudre des cas triviaux –puis en les combinant résoudre des cas complexes

29 29 Bilan  un algorithme récursif peut être transformé en algorithme itératif (ne le faire que si on voit que l'algorithme "patine" ou besoin impérieux)  un programme itératif n'est pas toujours plus efficace qu'un programme récursif  la récursivité est centrale en informatique dite théorique pour distinguer les problèmes (problèmes calculables) qu'une machine peut résoudre en temps fini en IA et en recherche opérationnelle pour résoudre des problèmes complexes en programmation pour traiter de manière simple de nombreux problèmes sur les arbres binaires (recherche, tri etc.)

30 30 Retenir  Un algorithme itératif n’est pas forcément plus rapide qu’un algorithme itératif  Certains algorithmes sont mieux traités par des algorithmes itératifs  D’autres sont mieux traités par des algorithmes récursifs

31 31 Auto-évaluation cours 6  Qu’est-ce que parcourir un arbre ?  Quels sont les parcours classiques sur les arbres ?  Les algorithmes itératifs sont-ils toujours plus efficaces que les algorithmes récursifs ? Réciproque ?  Donner des exemples de parcours en profondeur à main gauche ?  Même question pour le parcours hiérarchique  Écrire en C les parcours classiques sur les arbres binaires étudiés en cours, en TD


Télécharger ppt "1 Algorithmique et structures de données en C É. Delozanne, L2-S4-prog4, Paris 5"

Présentations similaires


Annonces Google