Compléments d algorithmique L1MPCIE 2008-2009 TD4 - Corrections Pointeurs Exercice 1 TYPE pint=^integer; VAR i:integer p1,p2:pint; BEGIN i:=1; p1:=@i; p1^:=2; new(p2); Exercice 2 Liste chaînée par pointeurs Soit L une liste dont chaque élément contient une valeur de type T. 1. Proposer une structure de données pour coder cette liste. TYPE liste = ^élément élément = ENREGISTREMENT val: T suiv: liste FIN ENREGISTREMENT Écrire les sous programmes suivants : 2. Tester si L est vide fonction listevide(donnée L : liste): booléen retourner L = NIL 3. Afficher les éléments de L (itératif, récursif) {itératif} fonction afficher1(donnée L : liste) tant que L NIL faire écrireécran(l^.val) L L^.suiv tant que {récursif} fonction afficher2(donnée L : liste): entier si L NIL alors écrireécran(l^.val) afficher2(l^.suiv) si valeur pointée valeur de i p1 pointe sur p2 pointe sur par p1 (p1^) e (valeur par défaut:0) 1 i 1 2 i 2 2 i 2 (notons-la Var) p2^:=3; 2 i 2 Var 3 p1:=p2; 2 Var 3 Var 3 p1^:=i+2; 2 Var 4 Var 4 dispose(p1); (Rq: p1 et p2 ont un rôle symétrique ici) new(p1); p1^:=5; 2 (valeur par défaut:nil) (valeur par défaut:nil) mémoire non allouée libération mémoire autre iable allouée 2 5 dynamiquement (valeur par défaut:nil) (valeur par défaut:nil) (valeur par défaut:nil) iable allouée dynamiquement (valeur par défaut:nil) (valeur par défaut:nil) valeur pointée par p2 (p2^) mémoire non allouée (ou val par défaut:0) libération mémoire S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 1
4. Déterminer la longueur de L (itératif, récursif) {itératif} fonction longueur1(donnée L : liste): entier compteur : entier compteur 0 tant que L NIL faire compteur compteur + 1 L L^.suiv tant que retourner compteur; {récursif} fonction longueur2(donnée L: liste): entier si L = NIL alors retourner 0 retourner 1 + longueur2(l^.suiv) si 5. Ajouter un élément e au de L procédure ajouterentête(donnée e: T, donnée modifiée L: liste) x: liste allouer(x) x^.val e x^.suiv L L x 6. Ajouter un élément e en de L (itératif, récursif) {itératif} procédure ajouterenfin1(donnée e: T, donnée modifiée L: liste) x,tmp : liste si L = NIL alors ajouterentête(e,l) tmp L {pour qu'en sortie L pointe toujours sur la tête} tant que tmp^.suiv NIL faire tmp tmp^.suiv; tant que allouer(x) x^.valeur e; tmp^.suiv x; si {récursif} procédure ajouterenfin2(donnée e: T, donnée modifiée L: liste) x: liste si L = NIL alors allouer(x) S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 2
x^.val e x^.suiv NIL L x ajouterenfin2(e, L^.suiv) si 7. Ajouter un élément e à L après le maillon d'adresse adr donnée, ou en de liste si adr n'est pas dans L (récursif) procédure ajouteraprèsadr(donnée e: T, adr: liste, donnée modifiée L : liste) x: liste si L = NIL allouer(x) x^.val e x^.suiv NIL L x si L = adr alors allouer(x) x^.val e x^.suiv L^.suiv L x ajouteraprèsadr(e, adr, L^.suiv) si 8. Tester l'appartenance d'un élément e à la liste L (itératif, récursif) {itératif} fonction appartient1(donnée e: T, L: liste): booléen tant que L NIL faire si l^.val = e alors retourner vrai si L L^.suiv tant que retourner faux; {récursif} fonction appartient2(donnée e: T, L: liste): booléen si L=NIL alors retourner faux si L^.val=e alors retourne vrai retourner appartient2(e, L^.suiv) si 9. Rechercher l'adresse de la première occurrence d'un élément e donné (récursif, itératif) {itératif} fonction rechercher1(donnee e: T, L: liste): liste tant que L NIL faire si L^.val = e alors retourner L S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 3
si L L^.suiv tant que retourner NIL; {récursif} fonction rechercher2(donnee e: T, L: liste): liste si L=NIL alors retourner NIL si L^.val=e alors retourner L rechercher2(e, L^.suiv) si 10. Ajouter à L un élément e après la première occurrence d'un élément x donné, ou en de liste si l'élément x n'est pas dans L procédure ajouteraprès1(donnée ajout, occurrence: T, donne modifiée L : liste) x: liste x rechercherx(occurrence, L) ajouteraprèsadr(ajout, x, L) {récursif} procédure ajouteraprès2(donnée ajout, occurrence: T, donne modifiée L : liste) x: liste si L=NIL alors allouer(x) x^.val ajout x^.suiv NIL L x si L^val=occurrence alors allouer(x) x^.val ajout x^.suiv L^.suiv L x ajouteraprès2(ajout, occurrence, L^.suiv) si 11. Supprimer le premier élément de L procédure supprimertête(donne modifiée L: liste) x: liste si L NIL alors x L L L^.suivant libérer(x) si 12. Supprimer un élément de L après le maillon d'adresse p donné (récursif) S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 4
procédure supprimeraprèsadr(donnée adr: liste ; donnée modifiée L: liste) x: liste si L NIL alors si L=adr alors si L^.suiv NIL alors x L^.suiv L^.suiv x^.suiv libérer(x) libérer(l) si supprimeraprèsadr(adr, L^.suiv) si si 13. Supprimer la première occurrence d'un élément e de L (itératif, récursif) {itératif} procédure supprimer1(donnée e: T, donnée modifiée L: liste) x,y: liste si L NIL alors si L^.val=e alors {supprimer la tête} x L L L^.suiv libérer(x) y L {pour qu'en sortie L pointe toujours sur la tête} tant que y^.suiv NIIL ET y^.suiv^.val e faire y y^.suiv tant que si y^.suiv NIL faire x y y y^.suiv libérer(x) si si {récursif} procédure supprimer2(donnée e: T, donnée modifiée L: liste) x:liste si L NIL alors si L^.val=e alors x L L L^.suiv libérer(x) supprimer2(e, L^.suiv) si si 14. Vider toute la liste L procédure vider(donnée modifiée L: liste) S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 5
tant que L NIL faire supprimertête(l); tant que Exercice 3 Liste d'entiers program ex3; { 1 } type Liste = ^Cellule; Cellule = record valeur : integer; suivant : Liste; { Pour test } procedure initialiser( l: Liste); l := nil; procedure ajouttete( l: Liste; e: integer); t: Liste; new(t); t^.suivant := l; t^.valeur := e; l := t; procedure afficher(l: Liste); if l <> nil then write(l^.valeur, ' '); afficher(l^.suivant); { 2 } function nboccurrences(l: Liste; a: integer): integer; if l = nil then nboccurrences := 0 if l^.valeur = a then nboccurrences := 1 + nboccurrences(l^.suivant, a) nboccurrences := nboccurrences(l^.suivant, a) { 3 } function trieecroissant(l: Liste): boolean; if l = nil then trieecroissant := true if l^.suivant = nil then trieecroissant := true trieecroissant := (l^.valeur < l^.suivant^.valeur) and trieecroissant(l^.suivant) S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 6
{ 4 } function trieeordreprecis(l: Liste; croissant: boolean): boolean; if l = nil then trieeordreprecis := true if l^.suivant = nil then trieeordreprecis := true trieeordreprecis := ((croissant and (l^.valeur < l^.suivant^.valeur)) or (not(croissant) and (l^.valeur > l^.suivant^.valeur))) and trieeordreprecis(l^.suivant, croissant) function triee(l: Liste): boolean; triee := trieeordreprecis(l, true) or trieeordreprecis(l, false) { 5 } procedure aff1sur2(l: Liste); if l <> nil then write(l^.valeur, ' '); if l^.suivant <> nil then aff1sur2(l^.suivant^.suivant); { 6 } { On décompose, c'est plus simple } {on peut aussi utiliser nboccurences écrite à la question 2} function apparait(l: Liste; e: integer): boolean; if l = nil then apparait := false if l^.valeur = e then apparait := true apparait := apparait(l^.suivant, e) function sansdoublons(l : Liste): boolean; if l = nil then sansdoublons := true if apparait(l^.suivant, l^.valeur) then sansdoublons := false sansdoublons := sansdoublons(l^.suivant) { 7 } { on pourrait aussi appeler un ajoutenqueue à chaque tour de boucle, ce qui a l'avantage d'être plus simple, mais l'inconvénient d'être peu performant, puisque parcours de la liste résultat à chaque ajout de valeur. } procedure fusionlistestriees(l1 : Liste; l2 : Liste; res : Liste); nouvvaleur: integer; dernierecellule: Liste; res := nil; dernierecellule := nil; while (l1 <> nil) or (l2 <> nil) do if (l2 = nil) or ((l1 <> nil) and (l2 <> nil) and (l1^.valeur < l2^.valeur)) then S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 7
nouvvaleur := l1^.valeur; l1 := l1^.suivant; end nouvvaleur := l2^.valeur; l2 := l2^.suivant; if (res = nil) then new(res); dernierecellule := res; res^.valeur := nouvvaleur; res^.suivant := nil; end new(dernierecellule^.suivant); dernierecellule := dernierecellule^.suivant; dernierecellule^.valeur := nouvvaleur; dernierecellule^.suivant := nil; { test } l1, l2, l3: Liste; initialiser(l1); ajouttete(l1, 12); ajouttete(l1, 9); ajouttete(l1, 8); initialiser(l2); ajouttete(l2, 14); ajouttete(l2, 10); ajouttete(l2, 2); ajouttete(l2, 1); writeln(triee(l1), triee(l2)); fusionlistestriees(l1, l2, l3); afficher(l3); writeln; end. Exercice 4 File d'attente 1.Écrire une procédure pour initialiser une file qui lui est passée en paramètre. procedure initialiserfifo( f: fifo); f.tete := NIL; f.queue := NIL; 2.Écrire une fonction qui teste si la file est vide. function estvide(f: fifo): boolean; if f.tete = NIL then estvide := true S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 8
estvide := false; 3.Écrire une procédure qui affiche une personne, de la forme [nom,prénom] ; et une procédure qui affiche les personnes présentent dans la file d'attente. procedure afficherpersonne(pers: personne); write('[',pers.nom,',',pers.prenom,']'); procedure afficherfifo(f: fifo); e: element; e := f.tete; while e <> NIL do afficherpersonne(e^.valeur); writeln(''); e := e^.suivant; 4.Écrire une procédure qui ajoute une personne dans la file d'attente. {l'ajout dans une FIFO se fait en queue} procedure ajouter(p: personne; f: fifo); nouveau: element; new(nouveau); nouveau^.valeur := p; if estvide(f) then f.tete := nouveau; f.queue^.suivant:= nouveau; f.queue := nouveau; 5.Écrire une fonction qui retourne l'avant dernier élément (s'il existe) de la file d'attente. function avantdernierelement(f: fifo): element; if not estvide(f) then if f.tete = f.queue then {1 seul element} avantdernierelement := NIL; end if f.tete^.suivant = f.queue then avantdernierelement := f.tete f.tete := f.tete^.suivant; avantdernierelement := avantdernierelement(f); end 6.Écrire une procédure qui retourne et enlève une personne de la file d'attente. {Suppression en tête dans une FIFO} procedure enlever( f: fifo; p: personne); S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 9
tmp: element; if not estvide(f) then enlever := f.tete^.valeur; tmp := f.tete^.suivant; dispose(f.tete); f.tete:=tmp; end 7.Écrire une fonction qui teste si deux personnes sont identiques. function personnesidentiques(p1,p2: personne): boolean; if (p1.nom=p2.nom) and (p1.prenom=p2.prenom) then personnesidentiques := true personnesidentiques := false; 8.Écrire une fonction qui teste si la file F 1 est incluse dans la file F 2. {test si F1 est inclue dans F2} function estincludans(f1,f2: fifo): boolean; e1,e2: element; sortie: boolean; e1 := f1.tete; e2 := f2.tete; sortie := false; while (e1<>nil) and (e2<>nil) do if personnesidentiques(e1^.valeur, e2^.valeur) then e1 := e1^.suivant; e2 := f2.tete; sortie := true; end e2 := e2^.suivant; sortie := false; estincludans := sortie; 9.Écrire la procédure sauver qui enregistre une file dans un fichier. La file et le nom du fichier (string) sont passés en paramètres. procedure sauver(nomfichier: string ; f: fifo); fichier: fichier_personne; pers: personne; e: element; assign(fichier, nomfichier); rewrite(fichier); {ouverture en écriture} e := f.tete; while e <> NIL do pers := enlever(f); S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 10
write(fichier, pers); close(fichier); 10.Écrire la fonction charger qui lit une file sauvegardée dans un fichier, et retourne un élément de type fifo. function charger(nomfichier: string): fifo; fichier: fichier_personne; pers: personne; f: fifo; assign(fichier, nomfichier); reset(fichier); {ouverture en lecture, se placer en } initialiserfifo(f); Repeat read(fichier, pers); ajouter(pers.nom,pers.prenom,f); Until eof (fichier) ; close(fichier); charger := f; Exercice 4 Liste de nombres premiers procedure listepremiers (n: integer; L : liste); L,b: liste; i,j,k: integer; L := NIL; for i:= n downto 2 do ajouterentête (i,l); b := L; k:= b^.contenu; while k*k <= n do for j := k to (n div k) do supprimerx (j*k, L); b := b^.suivant; k := b^.contenu; end. Exercice 5 Arbre binaire de caractères 1.Écrire une procédure qui teste si un noeud est une feuille. function estfeuille(a: arbre): boolean; if a = NIL then estfeuille := false estfeuille := (a^.gauche=nil) and (a^.droite=nil); 2.Écrire une procédure qui affiche les valeurs de l'arbre, selon un parcours infixé (on dit S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 11
aussi symétrique). Vous devriez-obtenir : ''D B E A C F'' sur l'exemple ci-dessus. {infixé <=> racine, puis sous-arbre Gauche, puis sous-arbre Droit} procedure afficherinfixe(a: arbre); if a <> NIL then write(a^.valeur,' '); afficherinfixe(a^.gauche); afficherinfixe(a^.droite); 3.Écrire une fonction qui retourne la taille de l'arbre, c-à-d le nombre de noeuds présents dans l'arbre. function taille(a: arbre): integer; {selon un parcours infixé} if a = NIL then taille := 0 taille := 1+ taille(a^.gauche) + taille(a^.droite); 4.Écrire une fonction qui recherche si un caractère est présent dans l'arbre, et retourne l'adresse du noeud. function rechercher(valeur: char ; a: arbre): arbre; tmp : arbre; if a = NIL then rechercher := NIL if a^.valeur=valeur then rechercher := a tmp := rechercher(valeur, a^.gauche); if tmp = NIL then rechercher := rechercher(valeur, a^.droite) rechercher := tmp; 5.Écrire une fonction qui teste si l'arbre est ordonné, c-à-d si la chaîne infixée des valeurs des noeuds correspond à un parcours ordonné croissant. function estordonne(a: arbre): boolean; gauche, droite : arbre; if a = NIL then estordonne := true gauche := a^.gauche; droite := a^.droite; if (gauche<>nil) and (droite<>nil) then estordonne := (gauche^.valeur<=a^.valeur) and (droite^.valeur>=a^.valeur) and estordonne(gauche) and estordonne(droite) S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 12
if gauche<>nil then estordonne := (droite^.valeur>=a^.valeur) and estordonne(droite) if droite<>nil then estordonne := gauche^.valeur<=a^.valeur and estordonne(gauche) estordonne := true; 6.Écrire une fonction qui retourne la hauteur de l'arbre, c-à-d le nombre maximum de noeuds rencontrés pour aller de la racine vers une feuille. '0' sera retourné si l'arbre est vide, '1' si l'arbre ne possède qu'un noeud, etc. function max(i,j: integer):integer; if i<j then max:=j max:=i function hauteur(a: arbre): integer; if a = NIL then hauteur := 0 if (a^.gauche=nil) and (a^.droite=nil) then hauteur := 1 hauteur := 1 + max( hauteur(a^.gauche), hauteur(a^.droite) ); 7.Écrire une fonction qui retourne le facteur d'équilibre d'un noeud, c-à-d la différence de la hauteur du sous-arbre gauche avec la hauteur du sous-arbre droit. (QUESTION SUPPRIMEE) function facteurequilibre(a: arbre): integer; if a = NIL then facteurequilibre := 0 facteurequilibre := hauteur(a^.gauche)-hauteur(a^.droite) end 8.Écrire une procédure qui affiche le mot de l'arbre, c-à-d une chaîne formée par les feuilles avec un sens de lecture de gauche à droite. procedure mot(a: arbre); if a <> NIL then if estfeuille(a) then write(a^.valeur) mot(a^.gauche); mot(a^.droite); 9.Écrire une fonction qui teste si l'arbre A 1 est égal à A 2. function estegal(a1,a2: arbre): boolean; {avec un parcours préfixé} S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 13
if (a1=nil) and (a2=nil) then estegal := true estegal := false; if (a1<>nil) and (a2<>nil) then if estfeuille(a1) and estfeuille(a2) and (a1^.valeur=a2^.valeur) then estegal := true estegal := false; if (not estfeuille(a1)) and (not estfeuille(a2)) then estegal := estegal(a1^.gauche,a2^.gauche) and estegal(a1^.droite,a2^.droite); S2MPCIE3 Compléments d'algorithmique TD4 Université d'angers 14