ASD 06/07 - Corrigé TD 7 Exercice 7.1 La fonction f transforme son paramètre, la liste L, en inversant tous les liens (le maillon précédent devient maillon suivant et donc le premier maillon devient le dernier) : f renverse la liste L. La fonction f appelle une fonction récursive, f_aux à deux paramètres : L1 est la partie de la liste déjà inversée, L2 est la partie de la liste qui reste à inverser. Algorithme itératif : On peut reprendre l algorithme récursif et le dérécursiviser. On utilise exprès les mêmes idéntificateurs de variables pour metter en évidence les liens avec la version récursive : à tout instant L2 est la partie de la liste qui reste à inverser (c est donc le paramètre), L1 est la partie de la liste déjà inversée, L sert à pointer sur la suite de L2 quand on ajoute à la liste L1 le maillon en tête de liste pointé par L2. fonction renverse_iter(val L2: ListedEntiers): ListedEntiers; var L1,L: ListedEntiers; L1:= NIL; tantque Non(ListeVide?(L2)) faire: L:= L2^.Sv; L2^.Sv:= L1; L1:= L2; L2:= L; fintanque; retourner L1; Remarquer que la première affectation et les deux dernières dans la boucle on les retrouve en tant que passage de paramètres dans la version récursive. Remarquer aussi que le test devient une boucle. 1
Exercice 7.2 1. La procédure concatène les deux listes à l adresse de la première (par exemple). procédure concatener(réf L1,L2: ListedeE); var tmp: ListedeE; tmp:= L1^.Sv; L1^.Sv:= L2^.Sv; L2^.Sv:= tmp; L1:= L2; L2:= NIL Remarque : complexité constante au lieu que proportionnelle à la longueur de la première liste dans le cas où elles ne seraient pas circulaires. 2. Primitives de pile : procédure Empiler(réf P: PileDeE, x:e); niou(q); q^.info:= x; si PileVide?(P) alors q^.sv:= q; P:= q; q^.sv:= P^.Sv; P^.Sv:= q; procédure Dépiler(réf P: PileDeE); q:= P^.Sv; si P^.Sv = P alors // il y a un seul élément P:= NIL; P^.Sv:= q^.sv; // P pointe toujours sur le fond de la Pile 2
fonction Valeur(val P: PileDeE): E; retourner((p^.sv)^.info); fonction PileVide?(val P: PileDeE): booléen; retourner(p = NIL); procédure ViderPile(réf P: PileDeE); q:= P^.Sv; tantque P^.Sv <> P faire: P^.Sv:= q^.sv; q:= P^.Sv; fintantque; P:= NIL; Primitives de file : procédure Enfiler(réf F: FileDeE, x:e); niou(q); q^.info:= x; si FileVide?(F) alors q^.sv:= q; F:= q; q^.sv:= F^.Sv; F^.Sv:= q; F:= q; // F pointe toujours sur la queue de la file 3
procédure Défiler(réf F: FileDeE); q:= F^.Sv; si F^.Sv = F alors // il y a un seul élément F:= NIL; F^.Sv:= q^.sv; fonction Valeur(val F: FileDeE): E; retourner((f^.sv)^.info); fonction FileVide?(val F: FileDeE): booléen; retourner(f = NIL); procédure ViderFile(réf F: FileDeE); q:= F^.Sv; tantque F^.Sv <> F faire: F^.Sv:= q^.sv; q:= F^.Sv; fintantque; F:= NIL; Remarques : Toutes les primitives ont compléxité constante, toutefois ces implémentations de Pile et File ne sont pas meilleures que celles avec tableaux sauf pour la possibilité d augmentation de la taille. Les primitives ont pratiquement le même code, sauf Empiler et Enfiler puisque dans la première le pointeur indique l élément le plus ancien (fond de la pile), dans la deuxième le pointeur indique l élément le plus recent (queue de la file) : ce choix permet d accéder en temps constant aux éléments à dépiler et défiler respectivement. 4
Exercice 7.3 Dans cet exercice on définit : type mon^ome = enreg Coef: réel; Exp: entier; Sv: ^mon^ome; finenreg; polyn^ome= ^mon^ome; On suppose que les monômes sont chaînés dans un ordre établi (croissant ou décroissant). On ne se pose pas la question de la normalisation des résultats, c.a.d. de l élimination des monômes nuls : c est plus simple d écrire une fonction de normalisation plutôt que d alourdir le code pour essayer de produire des polynômes résultats déjà normalisés. 1. Somme : on a intêret à écrire une fonction récursive qui retourne le polynôme résultat (l algorithme itératif demande de traiter à part le cas du premier élément, ce qui donne une duplication de code lourde). fonction somme(val P1: polyn^ome, val P2: polyn^ome): polyn^ome; var p:^mon^ome; si(p1=nil et P2=NIL) alors retourner nil; niou (p); si(p1!=nil et (P2=NIL ou (P2!=NIL et P1^.Exp>P2^.Exp))) alors p^.coef:=p1.coef; p^.exp:=p1.exp; p^.sv:=somme(p1^.sv, P2); retourne p; si(p2!=nil et (P1=NIL ou (P1!=NIL et P1^.Exp<P2^.Exp))) alors p^.coef:=p2.coef; p^.exp:=p2.exp; p^.sv:=somme(p1, P2^.Sv); retourne p; p^.coef:=p1.coef+p2.coef; p^.exp:=p1.exp; p^.sv:=somme(p1^.sv, P2^.Sv); retourne p; 5
2. Dérivée (on s inspire de copier_liste_rec) : fonction dérivée(val P: polyn^ome): polyn^ome; si P <> NIL alors retourne dérivée_aux(p); erreur; // par exemple...ou bien test avant appel fonction dérivée_aux(val P: polyn^ome): polyn^ome; var d:^mon^ome; si P <> NIL alors niou(d); d^.coef:= P^.Coef * P^.Exp; d^.exp:= P^.Exp - 1; d^.sv:= dérivée_aux(p^.sv); retourne(d); retourne NIL; 6