Corrigé de examen de programmation avancée ENSIIE, semestre 2 mercredi avri 20 Exercice : Compiation séparée ( points). En C : gcc -Wa -ansi -c A.c En OCam : ocamc -c A.m 2. En C : gcc -Wa -ansi -o prog A.o B.o C.o D.o E.o En OCam : ocamc -o prog D.cmo E.cmo C.cmo A.cmo B.cmo. I faut recompier E et C.. En C : prog: A.o B.o C.o D.o E.o gcc -Wa -ansi -o $@ $^ A.o: C.h D.h B.o: C.h C.o: C.h D.h E.h D.o: D.h E.o: E.h En OCam : prog: D.cmo E.cmo C.cmo A.cmo B.cmo ocamc -o $@ $^ A.cmo: C.cmi D.cmi B.cmo: C.cmi C.cmo: C.cmi D.cmi E.cmi D.cmo: D.cmi E.cmo: E.cmi %.cmo: %.m ocamc -c $< %.cmi: %.mi ocamc -c $< Exercice 2 : Représentation d arbres à k-fis (8 points). En C, représentation standard : struct arbre { int rang; struct arbre* fis[k]; ;
En C, représentation FGFD : struct arbre { struct arbre* fis_gauche; struct arbre* frere_droit; ; En OCam, représentation standard : type arbre = Noeud of int * (arbre array) En OCam, représentation FGFD : type arbre = Noeud of (arbre option) * (arbre option) 2. Représentation standard : 2 0 0 0 0 0 0 0 0 0 0 Représentation FGFD :. a) En C, représentation standard : struct arbre nieme_fis (struct arbre a, int i) { return *(a.fis[i]); En C, représentation FGFD : struct arbre nieme_fis (struct arbre a, int i) { struct arbre* res = a.fis_gauche; whie (i > 0) { res = res->frere_droit; i--; ; return *res; 2
En OCam, représentation standard : et nieme_fis a i = Noeud (r, t) -> t.(i) En OCam, représentation FGFD : et rec nieme_frere a i = if i = 0 then a ese Noeud(_, Some b) -> nieme_frere b (i-) Noeud(_, None) -> faiwith "pas assez de frere" et nieme_fis a i = Noeud(Some f, _) -> nieme_frere f i Noeud(None, _) -> faiwith "pas de fis" b) En C, représentation standard : struct arbre ajoute_fis_a_gauche(struct arbre a, struct arbre b) { if (a.rang >= k) a.rang++; int i; for (i = a.rang - ; i > 0; i--) { a.fis[i] = a.fis[i-]; ; a.fis[0] = &b; En C, représentation FGFD : struct arbre ajoute_fis_a_gauche(struct arbre a, struct arbre b) { b.frere_droit = a.fis_gauche; a.fis_gauche = &b; En OCam, représentation standard : et rec decae_tabeau t n = if n > 0 then begin t.(n) <- t.(n-); decae_tabeau t (n-) end et ajoute_fis_a_gauche a b = Noeud(r, t) -> if r >= k then a ese begin decae_tabeau t r; t.(0) <- b; Noeud(r +, t)
end En OCam, représentation FGFD : et ajoute_fis_a_gauche a b = match a, b with Noeud(fga, fda), Noeud(fgb, None) -> Noeud(Some (Noeud(fgb, fga)), fda) _ -> faiwith "b a déjà un frere" c) En C, représentation standard : struct arbre ajoute_fis_a_droite(struct arbre a, struct arbre b) { if (a.rang >= k) a.fis[a.rang] = &b; a.rang++; En C, représentation FGFD : struct arbre ajoute_fis_a_droite(struct arbre a, struct arbre b) { struct arbre* res = a.fis_gauche; whie (res) res = res->frere_droit; res->frere_droit = &b; En OCam, représentation standard : et ajoute_fis_a_droite a b = Noeud(r, t) -> if r >= k then a ese begin t.(r) <- b; Noeud(r+, t) end En OCam, représentation FGFD : et rec ajoute_frere_a_droite a b = None -> Some(b) Some(Noeud(fg, fd)) -> Some(Noeud(fg, ajoute_frere_a_droite fd b)) et ajoute_fis_a_droite a b = Noeud(fg, fd) -> Noeud(ajoute_frere_a_droite fg b, fd) d) En C, représentation standard : struct arbre supprimer_fis(struct arbre a, int i) { a.rang--; for(; i < a.rang; i++) a.fis[i] = a.fis[i+];
En C, représentation FGFD : struct arbre supprimer_fis(struct arbre a, int i) { if (i == 0) { a.fis_gauche = a.fis_gauche->frere_droit; ; struct arbre* b = a.fis_gauche; whie (i > ) { b = b->frere_droit; i--; ; b->frere_droit = b->frere_droit->frere_droit; En OCam, représentation standard : et rec decaer_droite t i n = if i < n then begin t.(i) <- t.(i+); decaer_droite t (i+) n end et supprimer_fis a i = Noeud(r, t) -> decaer_droite t i (r - ); Noeud(r -, t) En OCam, représentation FGFD : et rec supprimer_frere a i = match a, i with Noeud(fg, Some(Noeud(fdg,fdd))), -> Noeud(fg, fdd) Noeud(fg, Some fd), _ -> Noeud(fg, Some (supprimer_frere fd (i-))) Noeud(_, None), _ -> faiwith "pas assez de frere" et supprimer_fis a i = match a, i with Noeud(Some(Noeud(fgg,fgd)), fd), 0 -> Noeud(fgd, fd) Noeud(Some fg, fd), _ -> Noeud(Some(supprimer_frere fg i), fd) Noeud(None, _), _ -> faiwith "pas assez de fis". Soit n e nombre de sous-arbres de a racine de a Fonction représentation standard représentation FGFD nieme_fis O() O(i) ajoute_fis_a_gauche O(n) O() ajoute_fis_a_droite O() O(n) supprimer_fis O(n i) O(i). L accès à un fis est pus rapide dans a représentation standard.
La représentation standard est pus avantageuse si on ajoute es sous-arbres à droite, aors ue a représentation FGFD est pus avantageuse si on es ajoute à gauche. La pace occupée en mémoire est meieure pour a représentation FGFD dans e cas où beaucoup de noeuds ne sont pas compets (c est-à-dire ont un nombre de noeuds strictement inférieur à k), ce ui est e cas des feuies par exempe. Exercice : Garbage coector et partage maxima ( points) 2. Les parties accessibes sont cees à partir de et. 2. On marue à partir des variabes du programme : 2 Puis on nettoie :. On recopie d abord (par exempe) 2 6
Puis 2 Et on change de moitié de mémoire :.. et tabe = creer 2 et hashcons = try rechercher tabe with Not_found -> inserer tabe ; et ni = hashcons et cons x = hashcons (x :: ) 6. et = cons ni in 7
et = cons ni in et = et h = cons 2 (cons (cons )) in List.t h in et = cons (cons ) in, 7. Après a première igne : Après a deuxième : Après a uatrième igne : 8
2 h Après e cons de a igne 7 : 2 À a fin : Exercice : Fonctions de hachage ( points). La vaeur de hachage vaut 00000000 xor c xor h xor i xor e xor n, soit 0000 xor 00000 xor 0000 xor 0000 xor 000, soit 00000 xor 0000 xor 0000 xor 000, soit 00000 xor 0000 xor 000, 9
soit 00000 xor 000, soit 0000. 2. La vaeur de hachage vaut 00000000 xor n xor i xor c xor h xor e, soit 000 xor 0000 xor 0000 xor 00000 xor 0000, soit 00000 xor 0000 xor 00000 xor 0000, soit 00000 xor 00000 xor 0000, soit 000000 xor 0000, soit 0000.. Si on a un anagramme c... c n et c π()... c π(n) avec une permutation π, a vaeur de hachage vaudra 0 xor c xor xor c n = 0 xor c π() xor xor x π(n) dans es deux cas. I y aura donc coision entre anagrammes.. La fonction combine ne doit pas être commutative, sinon a vaeur de hachage est a même pour es anagrammes, ce ui entraîne des coisions.. La fonction combine(x, y) = x * 9 + y n est jamais commutative (on peut vérifier ue si combine(x,y) = combine(y,x) aors x = y), ee ne pose a priori pas de probème, au moins pour es anagrammes. 6. On peut définir une fonction de hachage de façon récursive : si arbre est vide, on retourne une certaine constante (par exempe 0) ; si on a un noeud contenant entier i avec comme fis fg et fd, on cacue récursivement a vaeur de hachage h fg du fis gauche et h fd du fis droit, et on retourne combine(h fg, combine(h fd, i)). 0