Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (* -------------------------------------------------------------------------- *)
- (* ----------------------- TP1 - IFT-3000 - Hiver 2017 ---------------------- *)
- (* -------------------------------------------------------------------------- *)
- (* Matricule étudiant: ......... *)
- (* -------------------------------------------------------------------------- *)
- (* -- PRINCIPALE FICHIER DU TP: FONCTIONS Ã COMPLÃTER ----------------------- *)
- (* -------------------------------------------------------------------------- *)
- #use "utiles.ml";;
- (******************************************************************************)
- (* Spécification *)
- (******************************************************************************)
- module type D_ARBO = sig
- type arbre
- val creer_branche : char list -> arbre
- val parcours : arbre -> char list -> char list * char list * arbre
- val nbr_arcs : arbre -> int
- val creer : string list -> arbre
- val de_fichier : string -> arbre
- val ajouter : arbre -> string -> unit
- val liste_mots : arbre -> string list
- val liste_par_prefixe : arbre -> string -> string list
- val membre : arbre -> string -> bool
- val supprimer : arbre -> string -> unit
- val supprimer_mots : arbre -> string list -> unit
- val sous_arbre : ?h_limit:int option -> arbre -> string -> arbre
- val show : arbre -> unit
- val ratio : arbre -> float
- val print_ratio : arbre -> unit
- end;;
- (******************************************************************************)
- (* Implantation *)
- (******************************************************************************)
- module D_Arbo (* : D_ARBO *) = struct
- open List
- open Utiles
- exception Non_Implante of string
- (* Principale structure de données utilisée par le dictionnaire arbo. *)
- (****************************************************************************)
- type arbre = Noeud of bool ref * (char * arbre) list ref
- (* Fonction retournant un arbre vide *)
- let vide () = Noeud(ref false,ref[])
- (* -- À IMPLANTER/COMPLÈTER (10 PTS) -------------------------------------- *)
- (* @Fonction : creer_branche : char list -> arbre *)
- (* @Description : retourne un arbre correspondant à une branche formant
- un mots *)
- (* @Precondition : aucune *)
- (* @Postcondition : l'arbre retourné correspond à une branche et est correct*)
- let rec creer_branche lc =
- try
- let firstChar = List.hd lc in
- if (List.length lc = 1) then
- Noeud(ref false, ref [(firstChar, Noeud(ref true, ref[]))])
- else
- Noeud(ref false, ref [(firstChar, creer_branche(List.tl lc))])
- with
- _ -> Noeud(ref true, ref[]);;
- (* -- À IMPLANTER/COMPLÈTER (10 PTS) -------------------------------------- *)
- (* @Fonction : parcours : arbre -> char list ->
- char list * char list * arbre *)
- (* @Description : Parcourt un arbre à partir d'une liste de caractères.
- Retourne: 1- la liste des caractères que l'on n'a pu
- rejoindre (n'existent pas dans le chemin tracée par la
- liste de caractères donnée en entrée. 2- la liste de
- caractères parcourus (visités). 3- et le sous-arbre
- atteint à la fin du parcours. *)
- (* @Precondition : aucune *)
- (* @Postcondition : l'arbre retourné est un sous-arbre de l'arbre en entrée *)
- let parcours a lc =
- let rec aux a lc visited = match a,lc with
- | Noeud(_,_), [] -> ([], [], a)
- | Noeud(_,tl), head::tail ->
- try
- let node = List.assoc head !tl in
- let(cantjoin, joined, subtree) = aux node tail (visited@[head]) in (cantjoin, head::joined, subtree)
- with
- Not_found -> (lc, [], a)
- in aux a lc [];;
- (* ------------------------------------------------------------------------ *)
- (* @Fonction : nbr_arcs : arbre -> int *)
- (* @Description : Retourne nombre arcs dans arbre *)
- (* @Precondition : aucune *)
- (* @Postcondition : le nombre retourné est correct *)
- let rec nbr_arcs a = match a with
- | Noeud(_,l) when l = ref [] -> 0
- | Noeud(_,l) ->
- (length !l) + fold_right (+) (map (fun (_,a) -> nbr_arcs a) !l) 0
- (* ------------------------------------------------------------------------ *)
- (* @Fonction : haut_limite : arbre -> int -> arbre *)
- (* @Description : Ã partir d'un arbre, retourne la partir de l'arbre
- limitée à une hauteur n *)
- (* @Precondition : n >= 0 *)
- (* @Postcondition : l'arbre retourné est un sous-arbre de celui en argument *)
- let rec haut_limite a n = match a,n with
- | Noeud(b,_),_ when n <= 0 -> Noeud(b,ref [])
- | Noeud(_,l),_ when l = ref [] -> a
- | Noeud(b,l),_ -> Noeud(b,ref (map (fun (c,a) -> c,haut_limite a (n-1)) !l))
- (* -- Ã IMPLANTER/COMPLÃTER (10 PTS) -------------------------------------- *)
- (* @Fonction : ajouter : arbre -> string -> unit *)
- (* @Description : Ajoute un mot à l'arbre *)
- (* @Precondition : aucune *)
- (* @Postcondition : effet de bord: l'arbre passé en argument comprend
- désormais le mot *)
- let ajouter a mot =
- let rec aux a' listchar found =
- (if ((implode found) = mot) then (let Noeud(b,_) = a' in b := true) else
- (let Noeud(_,arr2) = (creer_branche listchar) in let Noeud(b,arr) = a' in arr := !arr@(!arr2);
- if (List.length !arr) <= 0 then b := true))
- in
- let pastrouve, trouve, sousarbre = parcours a (explode mot) in aux sousarbre pastrouve trouve;;
- (* -- Ã IMPLANTER/COMPLÃTER (15 PTS) -------------------------------------- *)
- (* @Fonction : liste_mots : arbre -> string list *)
- (* @Description : Retourne la liste des mots de l'arbre *)
- (* @Precondition : aucune *)
- (* @Postcondition : la liste retournée est correcte *)
- let liste_mots a =
- let sort_and_remove_duplicates l =
- let sl = List.sort compare l in
- let rec go l acc =
- match l with
- | [] -> List.rev acc
- | [x] -> List.rev (x::acc)
- | (x1::x2::xs) ->
- if x1 = x2
- then go (x2::xs) acc
- else go (x2::xs) (x1::acc)
- in go sl []
- in
- let rec fold l =
- let rec iter head_list =
- match head_list with
- | [] -> []
- | head::tail -> head@(iter tail)
- in
- match l with
- | [] -> []
- | head::tail -> (iter head)@(fold tail)
- in
- let rec aux a' acc liste =
- match a' with
- | Noeud(b,tl) when tl = ref [] -> if !b then !liste@[(implode acc)] else !liste
- | Noeud(b,tl) -> sort_and_remove_duplicates (fold [(List.map (fun (c,a2) -> (aux a2 (acc@[c]) (if !b then (ref (!liste@[(implode acc)])) else liste))) !tl)])
- in aux a [] (ref []);;
- (* -- Ã IMPLANTER/COMPLÃTER (8 PTS) --------------------------------------- *)
- (* @Fonction : creer : string list -> arbre *)
- (* @Description : Crée un arbre à partir d'une liste de mots *)
- (* @Precondition : aucune *)
- (* @Postcondition : l'arbre retourné est correct *)
- let creer l =
- let rec ajoutermot a lm =
- match a, lm with
- | Noeud(_,_), [] -> a
- | Noeud(b,_), [""] -> b := true; a
- | Noeud(b,tl), head::tail ->
- if (List.length !tl) > 0 then ((ajouter a head) ; (ajoutermot a tail)) else (ajoutermot (creer_branche (explode head)) tail)
- in
- ajoutermot (vide ()) l;;
- (* ------------------------------------------------------------------------ *)
- (* @Fonction : de_fichier : string -> arbre *)
- (* @Description : Crée un arbre à partir des mots présents dans un fichier*)
- (* @Precondition : Chaque ligne du fichier comprend un mot *)
- (* @Postcondition : l'arbre retourné est correct *)
- let de_fichier f =
- creer (read_lines_file f)
- (* -- Ã IMPLANTER/COMPLÃTER (7 PTS) --------------------------------------- *)
- (* @Fonction : membre: arbre -> string -> bool *)
- (* @Description : Teste si un mot est dans un arbre *)
- (* @Precondition : aucune *)
- (* @Postcondition : vrai si mot existe; faux, sinon *)
- let membre a mot =
- let notfound, found, tree = parcours a (explode mot) in
- if ((implode found) = mot) && (let Noeud(b,_) = tree in !b = true) then
- true
- else
- false
- (* -- Ã IMPLANTER/COMPLÃTER (15 PTS) -------------------------------------- *)
- (* @Fonction : supprimer : arbre -> string -> unit *)
- (* @Description : Supprime un mot d'un arbre *)
- (* @Precondition : Mot existe das l'arbre; autrement exception Not_found *)
- (* @Postcondition : effet de bord: l'arbre passé en argument ne comprend
- désormais plus le mot *)
- let supprimer a mot =
- let get_node a letters = let (_, _, node) = parcours a letters in node in
- let remove_last lst = if (List.length lst) > 0 then List.rev (List.tl (List.rev lst)) else [] in
- let rm_char_in_list li le = List.filter (fun (c, _) -> (c <> le)) li in
- let rec aux root letters i =
- if (List.length (explode mot)) = (i+1) then (let Noeud(b, _) = get_node root letters in b := false; aux root (remove_last letters) (i-1))
- else if i > 0 then (let Noeud(b, arr) = get_node root letters in let len = (List.length !arr) in arr := (rm_char_in_list !arr (List.nth letters (i-1))); if !b = false && len <= 1 then (aux root (remove_last letters) (i-1)))
- in if not (membre a mot) then raise Not_found else aux a (explode mot) ((List.length (explode mot)) - 1)
- (* -- Ã IMPLANTER/COMPLÃTER (5 PTS) --------------------------------------- *)
- (* @Fonction : supprimer_mots : arbre -> string list -> unit *)
- (* @Description : Supprime une liste de mots d'un arbre *)
- (* @Precondition : Mots existent das l'arbre; autrement exception Not_found*)
- (* @Postcondition : effet de bord: l'arbre passé en argument ne comprend
- désormais plus les mots *)
- let supprimer_mots a l =
- let rec aux a' l' =
- match l' with
- | [] -> ()
- | head::tail -> supprimer a' head; aux a' tail
- in aux a l;;
- (* -- Ã IMPLANTER/COMPLÃTER (10 PTS) -------------------------------------- *)
- (* @Fonction : sous_arbre: ?h_limit:int option -> arbre -> string ->
- arbre *)
- (* @Description : Ã partir d'un mot, retourne le sous-arbre qui suit les
- caractères formant ce mot; si h_limit=None, retourne
- tout le sous-arbre; sinon, Some(n), retourne le sous-
- arbre limité à une hauteur = n *)
- (* @Precondition : Mot existe dans l'arbre; autrement exception Not_found *)
- (* @Postcondition : l'arbre retourné est un sous-arbre de celui en argument *)
- let sous_arbre ?(h_limit = None) a mot =
- let (a', _, _) = (parcours a (explode mot)) in
- if not (a' = []) then raise Not_found
- else let notfound, found, sousarbre = parcours a (explode mot) in
- if h_limit = None then sousarbre else haut_limite sousarbre (match h_limit with Some c -> c | None -> 0);;
- (* -- Ã IMPLANTER/COMPLÃTER (10 PTS) -------------------------------------- *)
- (* @Fonction : liste_par_prefixe: arbre -> string -> string list *)
- (* @Description : Ãtant donné un arbre, et un prefixe (mot), retourne tous
- les mots de l'arbre ayant ce prefixe; la liste des mots
- retournée est triée, par ordre croissant, selon la taille
- de ces mots *)
- (* @Precondition : aucune *)
- (* @Postcondition : la liste retournée est correcte *)
- let liste_par_prefixe a m =
- match m with
- | "" -> liste_mots a
- | e -> let notfound, found, tree = parcours a (explode m) in if not (notfound = []) then raise Not_found else List.map (fun x -> m ^ x) (liste_mots tree);;
- (* ------------------------------------------------------------------------ *)
- (* @Fonction : show: arbre -> unit *)
- (* @Description : Affiche un arbre sous forme graphique, grâce à l'outil
- dotty (http://www.graphviz.org/) *)
- (* @Precondition : aucune *)
- (* @Postcondition : aucune *)
- let show (Noeud(b,_) as a) =
- let format x y c =
- Printf.sprintf "%s -- %s [ label = \"%c\" ];\n" x y c in
- let init n s =
- let s' = ref "" in
- for i = 1 to n do s' := !s' ^ s ^ (string_of_int i) ^ "; " done;
- !s'
- in
- let node b cf ct = match !b with
- | true -> "t" ^ (string_of_int !ct)
- | false -> "f" ^ (string_of_int !cf)
- in
- let rec show_tree (Noeud(b,l)) cf ct =
- let node_b = node b cf ct in
- fold_left (fun (s,cf,ct) (c,(Noeud(b',_) as a)) ->
- let _ = if !b' then incr ct else incr cf in
- let node_b' = node b' cf ct in
- let (s',cf',ct') = show_tree a cf ct in
- (s ^ (format node_b node_b' c) ^ s', cf', ct')
- ) ("",cf,ct) !l
- in
- let (cf,ct) = if !b then (ref 0,ref 1) else (ref 1,ref 0) in
- let (body,cf,ct) = show_tree a cf ct in
- let graphviz =
- "graph G {\n" ^
- "node [shape=none]; {node [label=\"false\"] " ^
- (init !cf "f") ^
- "}\nnode [shape=none]; {node [label=\"true\" fontcolor=blue] " ^
- (init !ct "t") ^
- "}\n\n" ^ body ^ "\n}\n"
- in
- let file = "graph.gv" in
- let fout = open_out file in
- output_string fout graphviz;
- close_out fout;
- ignore (Sys.command ("xdot " ^ file));
- ()
- (* ------------------------------------------------------------------------ *)
- (* @Fonction : ratio: arbre -> float *)
- (* @Description : retourne le ratio entre le nombre total de caractères
- présent dans tous les mots du dictionnaire et le nombre
- de caractères (arcs) effectivement présent dans l'arbre *)
- (* @Precondition : aucune *)
- (* @Postcondition : aucune *)
- let ratio a =
- let n1 = fold_right (fun x acc -> (String.length x) + acc) (liste_mots a) 0
- and n2 = nbr_arcs a in
- abs_float((1.0 -. (float(n2) /. float(n1)))) *. 100.0
- (* ------------------------------------------------------------------------ *)
- (* @Fonction : print_ratio: arbre -> unit *)
- (* @Description : Affiche le ratio de (gain en) stockage *)
- (* @Precondition : aucune *)
- (* @Postcondition : aucune *)
- let print_ratio a =
- print_endline
- ("Ratio de stockage : " ^ string_of_int(int_of_float(ratio a)) ^ "%")
- end;;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement