\documentclass[10pt]{article} \usepackage{amsmath,amssymb,fancybox,fancyhdr,lastpage,a4,mdwlist} \topmargin-0.5cm \headheight20pt \textheight23cm \textwidth17.5cm \oddsidemargin-1cm \evensidemargin0cm \parindent0pt \def\[{[\![} \def\]{]\!]} \begin{document} \renewcommand{\labelenumi}{\arabic{enumi})} \renewcommand{\labelenumii}{\alph{enumii})} \renewcommand{\labelenumiii}{\roman{enumiii})} \pagestyle{fancy} \lhead{{\bf MPSI option info}} \chead{} \rhead{TP 3~: arbres, types} \lfoot{\sl Lyc\'ee Chateaubriand} \cfoot{} \rfoot{\thepage/\pageref{LastPage}} \renewcommand{\footrulewidth}{0.4pt} \begin{enumerate} \item La fonction r\'ecursive s'\'ecrit facilement : \begin{verbatim} let rec taille = function | [] -> 0 | _ :: q -> 1 + taille q ;; \end{verbatim} \item On utilise un accumulateur qui commencera à la liste vide \texttt{[]} et contiendra à la fin toutes les valeurs de la liste \texttt{l} ins\'er\'ees dans l'ordre inverse : \begin{verbatim} let miroir l = let rec parcours accu = function | [] -> accu | t::q -> parcours (t::accu) q in parcours [] l ;; \end{verbatim} \item Pour les fonctions suivantes, on fait comme le sugg\`ere l'\'enonc\'e et on force le type des arguments : \begin{verbatim} let new_file () : 'a file = [], [];; \end{verbatim} \item Une file est vide si et seulement si les deux listes \texttt{arrive} et \texttt{repart} sont vides : \begin{verbatim} let est_vide (f : 'a file) = (f = ([], []));; \end{verbatim} \item On peut utiliser \texttt{fst} et \texttt{snd} pour r\'ecup\'erer \texttt{arrive} et \texttt{repart} : \begin{verbatim} let enfile x (f : 'a file) : 'a file = (x::(fst f), snd f);; \end{verbatim} On peut aussi utiliser un \texttt{match ... with} : \begin{verbatim} let enfile x (f : 'a file) : 'a file = match f with | arrive, repart -> (x :: arrive), repart \end{verbatim} \item Le sujet ne pr\'ecisait rien, mais on peut utiliser \texttt{failwith "File vide"} pour renvoyer une erreur si les deux listes \texttt{repart} et \texttt{arrive} sont vides : \begin{verbatim} let defile (f : 'a file) : 'a * 'a file = match f with | a, t::q -> t, (a, q) (* s'il y a une valeur dans repart *) | a, [] -> match miroir a with | [] -> failwith "File vide" | t::q -> t, ([], q) ;; \end{verbatim} \stepcounter{enumi} \item On ajoute les tailles des deux listes : \begin{verbatim} let longueur (f : 'a file) = match f with a, r -> (taille a) + (taille r) ;; \end{verbatim} \item On se rappelle que \texttt{\textasciicircum} fait la concat\'enation de deux chaines de caract\`eres : \begin{verbatim} let elements (f : int file) = let rec ecrire = function | [] -> "" | a::[] -> string_of_int a | t::q -> string_of_int t ^ ">>>" ^ (ecrire q) in ecrire (miroir (fst f) @ snd f) ;; \end{verbatim} \item \begin{verbatim} let arbre_ex = N(N(N(V, 2, V), 15, N(V, 22, V)), 28, N(V, 41, V));; \end{verbatim} On peut aussi \'ecrire une fonction \texttt{feuille} qui simplifie l'\'ecriture de \texttt{N(V, x, V)} : \begin{verbatim} let feuille x = N(V, x, V);; let arbre_ex = N(N(feuille 2, 15, feuille 22), 28, feuille 41);; \end{verbatim} \item Les deux fonctions ont la m\^eme forme, la \texttt{hauteur} utilise le \texttt{max} des hauteurs des fils gauche et droite, et la \texttt{taille} utilise la somme : \begin{verbatim} let rec hauteur = function | V -> -1 | N (g, _, d) -> 1 + max (hauteur g) (hauteur d) ;; let rec taille = function | V -> 0 | N (g, _, d) -> 1 + (taille g) + (taille d) ;; \end{verbatim} \item C'est comme \texttt{somme} mais avec \texttt{e +} si on trouve un n{\oe}ud \'etiquett\'e par \texttt{e} au lieu de \texttt{1 +} : \begin{verbatim} let rec somme = function | V -> 0 | N (g, e, d) -> e + (somme g) + (somme d) ;; \end{verbatim} \item On ne peut pas faire autrement que d'utiliser une concat\'enation de listes (\texttt{@}) : \begin{verbatim} let rec liste_etiquettes = function | V -> [] | N (g, e, d) -> e :: (liste_etiquettes g) @ (liste_etiquettes d) ;; \end{verbatim} \item On utilise un \texttt{match ... with} avec un \texttt{when e = f} : \begin{verbatim} let rec descendants e = function | V -> [] | N (_, f, _) as a when e = f -> liste_etiquettes a | N (g, _, d) -> (descendants e g) @ (descendants e d) ;; \end{verbatim} \item C'est plus compliqu\'e. Une fa\,con de l'\'ecrire, avec une fonction r\'ecursive, est la suivante : \begin{verbatim} let hamming n = let rec aux h2 h3 h5 n = if n=0 then [] else let e2, hp2 = defile h2 in let e3, hp3 = defile h3 in let e5, hp5 = defile h5 in let e = min (min e2 e3) e5 in e::(aux (enfile (2*e) (if e=e2 then hp2 else h2)) (enfile (3*e) (if e=e3 then hp3 else h3)) (enfile (5*e) (if e=e5 then hp5 else h5)) (n-1)) in aux (enfile 1 (new_file())) (enfile 1 (new_file())) (enfile 1 (new_file())) n ;; \end{verbatim} \item La suite est plus compliqu\'ee. \begin{verbatim} type dict = char arbre;; let rec estDansDict mot (db : dict) = match (mot, db) with | (_, V) -> false | ([], N (gauche, lettre, droit)) -> lettre = '$' | (l::fin_mot, N (gauche, lettre, droit)) -> if l = lettre then estDansDictBin fin_mot gauche else estDansDictBin mot droit ;; let contenuDict (db : dict) = let rec parcours prefixe = function | V -> [] | N (gauche, lettre, droit) -> if lettre = '$' then (miroir prefixe)::(parcours prefixe droit) else (parcours (lettre::prefixe) gauche) @ (parcours prefixe droit) in parcours [] db ;; let rec ajoutDict mot (db : dict) : dict = match mot, db with | ([], V) -> N (V, '$', V) | ([], N (gauche, lettre, droit)) -> if lettre = '$' then db else N (V, n, db) | (car::fin_mot, V) -> N (ajoutDict fin_mot V, car, V) | (car::fin_mot, N (gauche, lettre, droit)) -> if lettre = car then N (ajoutDict fin_mot gauche, lettre, droit) else N (gauche, lettre, ajoutDict mot droit) ;; \end{verbatim} \end{enumerate} \end{document}