Arbres n-aires
Transcription
Arbres n-aires
Arbres n-aires 14/04/06 Bac2 - JMD - Arbrnair NOEUD pcontenu MAILLON LISTE plstsucs psuiv psuiv pprec pprec pcontenu pcontenu pdebut pfin pcontenu pcontenu plstsucs plstsucs psuiv pdebut pdebut pprec pfin pfin pcontenu Arbre n-aire Bac2 - JMD - ArbrNair 1 Bac2 - JMD - ArbrNair 2 Fonctions du module ArbrNair /*-----------------------------------------------------------------------------------------------------------------Crée et initialise un noeud de contenu pointé par <q>. Retourne l'adresse du noeud créé. Retourne NULL en cas d'erreur. NB Le noeud mémorise l'adresse du contenu sans plus. ------------------------------------------------------------------------------------------------------------------*/ NOEUD * ANCreer_Noeud(void * q); /*----------------------------------------------------------------------------------------------------------------Ajoute un sous-arbre n-aire <an> à un noeud <a>. Retourne 1 en cas de succès et 0 dans le cas contraire (problème d'allocation par exemple). ------------------------------------------------------------------------------------------------------------------*/ int ANAjoutSArbre(ARBRNAIR an, NOEUD * a); /*-----------------------------------------------------------------------------------------------------------------Construit un arbre n-aire d'adresse <a> à l'aide de la fonction <ConstrArbrNair> fournie par l'appelant. Retourne 0 en cas d'erreur et 1 dans le cas contraire.Une valeur nulle dans <*a> indique un arbre vide. ------------------------------------------------------------------------------------------------------------------*/ int ANConstruire(ARBRNAIR *a, int ConstrArbrNair(ARBRNAIR *)); /*----------------------------------------------------------------------------------------------------------------Affiche l'arbre n-aire donné par l'adresse de son noeud racine <a> sous forme d'une expression parenthésée conforme à la grammaire suivante : <arbrnair> ::= <arbrnairs> ::= <etiquette> <lettresouchiffres> ::= ::= ( <etiquette> <arbrnairs> ) | empty <arbrnair> <arbrnairs> | empty <lettre> <lettresouchiffres> <lettre> <lettresouchiffres> | <chiffre> <lettresouchiffres> | empty NB Une étiquette de n ud <etiquette> n’est jamais vide! La fonction <AffichContenu> fournie par l'appelant permet d'afficher le contenu d'un noeud. ------------------------------------------------------------------------------------------------------------------*/ void ANAfficher(ARBRNAIR a, void AffichContenu(void *)); 14/04/06 Bac2 - JMD - Arbrnair 3 Fonctions du module ArbrNair (suite) /*---------------------------------------------------------------------------------------------------------------Retourne la profondeur d'un arbre n-aire donné par l'adresse de son noeud racine <a>. La profondeur d'un arbre est le nombre de noeuds sur le plus long chemin de la racine à une feuille (noeud sans successeur). La profondeur de l'arbre vide (pointeur sur racine null, sans noeud) est 0. Définition récursive : la profondeur d'un arbre n-aire est la profondeur du plus profond de ses s-arbres augmentée de 1. ----------------------------------------------------------------------------------------------------------------*/ int ANProfondeur(ARBRNAIR a); /*--------------------------------------------------------------------------------------------------------------Détruit un arbre n-aire donné par l'adresse d'un emplacement <*a> qui contient l'adresse de son noeud racine. La destruction d'un arbre n-aire consiste en la libération de tous les emplacements de mémoire dynamique (obtenus par malloc) qu'il occupe. Après la destruction, la fonction range la valeur NULL dans l'emplacement <*a> pour signifier que l'arbre résultant est vide. Définition récursive : Détruire un arbre n-aire, c'est détruire ses sous-arbres et libérer la place occupée par son noeud racine. La fonction <LibererContenu> fournie par l'appelant permet de libérer lecontenu d'un noeud. ----------------------------------------------------------------------------------------------------------------*/ void ANDetruire(ARBRNAIR * a, void LibererContenu(void *)); 14/04/06 Bac2 - JMD - Arbrnair 4 Fonctions du module Liste utilisées dans le module Arbrnair /* -----------------------------------------------------------------------------------------------------------------Crée une liste vide (pas de maillon) et en retourne l'adresse. ------------------------------------------------------------------------------------------------------------------ */ LISTE * ListCreer(void); /* -----------------------------------------------------------------------------------------------------------------Ajoute un maillon avant le premier maillon actuel dans la liste <plst>, lui attache le contenu d'adresse <pcont> et retourne l'adresse du maillon ajouté. ------------------------------------------------------------------------------------------------------------------ */ MAILLON * ListAjouterDeb(LISTE *plst, void * pcont); /* -----------------------------------------------------------------------------------------------------------------Retourne l'adresse du premier maillon de la liste <plst>. ------------------------------------------------------------------------------------------------------------------ */ MAILLON * ListDebut(LISTE *plst); /* -----------------------------------------------------------------------------------------------------------------Retourne l'adresse du maillon qui suit le maillon d'adresse <pcourant> dans la liste <plst>. ------------------------------------------------------------------------------------------------------------------ */ MAILLON * ListSuivant( MAILLON * pcourant); /* -----------------------------------------------------------------------------------------------------------------Retourne l'adresse du contenu du maillon d'adresse <pcourant>. ------------------------------------------------------------------------------------------------------------------ */ void * ListDonContenu(MAILLON * pcourant); /* -----------------------------------------------------------------------------------------------------------------Met le contenu du maillon d'adresse <pcourant> à la valeur <pcontenu>. ------------------------------------------------------------------------------------------------------------------ */ void ListMetContenu(MAILLON * pcourant, void * pcont); /* -----------------------------------------------------------------------------------------------------------------Détruit la liste <plst> y compris ses contenus et retourne NULL. ------------------------------------------------------------------------------------------------------------------ */ LISTE * ListDetruire(LISTE * plst); 14/04/06 Bac2 - JMD - Arbrnair 5 Visite en profondeur d’abord d’un arbre naire void VisiterProfondAux (ARBRNAIR arbrnair) { MAILLON * p; ARBRNAIR a; printf("%s ",arbrnair->pcontenu); p=ListDebut(arbrnair->plstsucs); while(p) { a=ListDonContenu(p); // Obtenir fils VisiterProfondAux(a); // Descente p=ListSuivant(p); // Essai fils suivant } return; // Plus ou pas de fils : // retour au parent ou // « backtracking » } void VisiterProfond(ARBRNAIR arbrnair) { if (arbrnair) VisiterProfondAux(arbrnair); printf("\n"); } 14/04/06 Bac2 - JMD - Arbrnair 6 Visiter pour trouver et traiter un noeud « particulier » (1) void CherchNoeudDansAux(ARBRNAIR arbrnair, int Propriete(NOEUD *), void Traitement(NOEUD *)) { MAILLON * p; ARBRNAIR a; if (Propriete(arbrnair)) { Traitement(arbrnair); return ; // Le noeud "racine" a la propriété requise // Traiter le noeud // retour en arrière au parent ou // "backtracking" } else { p=ListDebut(arbrnair->plstsucs); while(p) { a=ListDonContenu(p);// Obtenir fils // Descente CherchNoeudDansAux(a,Propriete,Traitement); p=ListSuivant(p); // Essai fils suivant } // Pas ou plus de fils(tous "visités") : return; // retour en arrière au parent } } 14/04/06 Bac2 - JMD - Arbrnair 7 Visiter pour trouver et traiter un noeud « particulier » (2) void CherchNoeudDans( ARBRNAIR arbrnair, int Propriete(NOEUD *), void Traitement(NOEUD *)) { if (arbrnair) CherchNoeudDansAux(arbrnair,Propriete,Traitement); printf("\n"); } int Tester_Propriete(NOEUD * pn) { return !strcmp(pn->pcontenu,"c"); } void Traiter_Noeud(NOEUD * pn) { printf("Encore un noeud de contenu %s\n",pn->pcontenu); } 14/04/06 Bac2 - JMD - Arbrnair 8 Programme principal test arbre n-aire #include <stdio.h> #include <crtdbg.h> #include "ArbrNair.h« // autres includes // Construit un arbre n-aire d'adresse <a>. int Construire(ARBRNAIR * a) { /*etc.*/ } // Affichage d'un contenu void AffEtiquet(char * etq) { /*etc.*/ } // Libération d'un contenu void LiberCont(void * pcont) { /*etc.*/ } int main() { ARBRNAIR arbrnair; arbrnair=NULL; if (ANConstruire(&arbrnair,Construire)) { printf("ok\n"); ANAfficher(arbrnair, AffEtiquet); VisiterProfond(arbrnair); printf("Profondeur : %d\n",ANProfondeur(arbrnair)); Cherch_Noeud_Dans(arbrnair, Tester_Propriete,Traiter_Noeud); } ANDetruire(&arbrnair,LiberCont); _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); _CrtDumpMemoryLeaks( ); return 0; } 14/04/06 Bac2 - JMD - Arbrnair 9 Visiter un arbre implicite pour trouver une solution • L’arbre n’est jamais totalement mémorisé et est alors qualifié d’« implicite » : – il est visité en profondeur d’abord, racine en premier puis sous-arbres de gauche à droite; – les successeurs de chaque n ud visité sont mémorisés jusqu’à ce que tous les descendants de ce n ud aient été visités aussi; – L’ensemble des n uds en cours de visite constituent un chemin dans l’arbre qui lui aussi est mémorisé (solution partielle à confirmer ou infirmer) 14/04/06 Bac2 - JMD - Arbrnair 10 Visiter un arbre implicite pour trouver une solution • Le chemin est mémorisé sous la forme d’une pile (des contenus) des n uds constitutifs, le (contenu du) n ud courant étant au sommet de la pile (FIFO). • Les (contenus des) candidats successeurs ou fils du n ud courant sont mémorisés dans une file (LIFO) pour être essayés successivement. 14/04/06 Bac2 - JMD - Arbrnair 11 Rappels Pile (LIFO) /* --------------------------------------------------------------------------Créer une pile vide (pas d’élément) et retourner son adresse. --------------------------------------------------------------------------- */ PILELIFO * PilCreer(void); /* --------------------------------------------------------------------------Retourner "vrai" si la pile <*ppil> est vide. Sinon retourner "faux". --------------------------------------------------------------------------- */ int PilVide(PILELIFO *ppil); /* --------------------------------------------------------------------------Empiler un contenu d’adresse <pcont> sur la pile <ppil>. --------------------------------------------------------------------------- */ void PilPush(PILELIFO *ppil, void * pcont); /* --------------------------------------------------------------------------Désempiler le contenu au sommet de la pile <ppil> et retourner l'adresse du contenu. --------------------------------------------------------------------------- */ void * PilPop(PILELIFO *ppil) ; /* --------------------------------------------------------------------------Destruire la pile <ppil> y compris les contenus et retourner NULL. --------------------------------------------------------------------------- */ PILELIFO * PilDetruire(PILELIFO * ppil); 14/04/06 Bac2 - JMD - Arbrnair 12 Rappels File (FIFO) /* --------------------------------------------------------------------------Créer une file vide (pas d’élément) et retourner son adresse. --------------------------------------------------------------------------- */ FILEFIFO * FilCreer(void); /* --------------------------------------------------------------------------Retourner "vrai" si la file <*pfil> est vide. Sinon retourner "faux". --------------------------------------------------------------------------- */ int FilVide(FILEFIFO *pfil); /* --------------------------------------------------------------------------Ajouter un contenu d’adresse <pcont> à la fin de la file <pfil>. --------------------------------------------------------------------------- */ void FilAjouter(FILEFIFO *pfil, void * pcont); /* --------------------------------------------------------------------------Retirer le contenu à la fin de la file <pfil> et retourner de l'adresse du contenu. --------------------------------------------------------------------------- */ void * FilRetirer(FILEFIFO *pfil) ; /* --------------------------------------------------------------------------Destruire la file <pfil> y compris les contenus et retourner NULL. --------------------------------------------------------------------------- */ FILEFIFO * FilDetruire(FILEFIFO * pfil); 14/04/06 Bac2 - JMD - Arbrnair 13 void Cherch_Solution( PILELIFO * part_sol,DATA input, int Est_Solution(PILELIFO *, DATA), void Traiter_Solution(PILELIFO *, DATA), void Determiner_Successeurs(PILELIFO *, DATA,FILEFIFO *)) { FILEFIFO * successeurs; // File des successeurs du noeud courant if (Est_Solution(part_sol,input)) { Traiter_Solution(part_sol,input); return ; } else { successeurs=FilCreer(); // Créer file vide. // Ajouter les successeurs du dernier noeud de <part_sol>. Determiner_Successeurs(part_sol,input,successeurs); while (!FilVide(successeurs)) { // Ajouter à solution partielle <part_sol>, un successeur de son dernier noeud PilPush(part_sol, FilRetirer(successeurs)); // Chercher une solution qui intègre (qui commence par) la solution partielle // augmentée de ce successeur Cherch_Solution(part_sol,input, Est_Solution, Traiter_Solution,Determiner_Successeurs); // BackTrack ou remontée : la recherche des solutions qui intègrent la solution // partielle augmentée est terminée. Retirer le successeur essayé. free(PilPop(part_sol)); } // Tous les successeurs du dernier noeud de la solution partielle <part_sol> essayés. // Retour de <part_sol> à sa valeur d'entrée. successeurs=FilDetruire(successeurs); return; } } 14/04/06 Bac2 - JMD - Arbrnair 14 Parties d’ensemble Fonctions complémentaires // entree_suppl différent de NULL bool Est_Sol (PILELIFO * solution, DATA entree_suppl) int n; MAILLON *pmaillon; pmaillon=ListDebut((LISTE *)solution); n=0; while(pmaillon) { n++; pmaillon=ListSuivant(pmaillon)); } return n==(*((int*)entree_suppl)); } { void Traiter_Sol (PILELIFO * solution, DATA entree_suppl) { int n; MAILLON *pmaillon; printf("{"); pmaillon=ListFin((LISTE *)solution); n=0; while(pmaillon) { n++; if(*((int *)ListDonContenu(pmaillon)))printf(" %d",n); pmaillon=ListPrecedent(pmaillon)); } printf("}\n"); } 14/04/06 Bac2 - JMD - Arbrnair 15 Parties d’ensemble Fonctions complémentaires void Determiner_Succes (PILELIFO * part_sol, DATA entree_suppl,FILEFIFO * successeurs) { int *pval1, *pval2; pval1=malloc(sizeof(int)); assert(pval1); (*pval1)=1; FilAjouter(successeurs,pval1); pval2=malloc(sizeof(int)); assert(pval2); (*pval2)=0; FilAjouter(successeurs,pval2); } 14/04/06 Bac2 - JMD - Arbrnair 16 Parties de l’ensemble des n premiers entiers positifs // #includes int main() { PILELIFO * plifo; int info=3; plifo=PilCreer(); // Parties de l’ensemble {1,2,3} // Solution partielle vide au départ Cherch_Solution(plifo,&info,Est_Sol,Traiter_Sol, Determiner_Succes); plifo=PilDetruire(plifo); _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); _CrtDumpMemoryLeaks( ); return 1; } 14/04/06 Bac2 - JMD - Arbrnair 17