.
..
prefixe-corrige.ml (download) (view)

(**************************************************************************)
(*                     Calcul du plus long complément                     *)
(**************************************************************************)
type etiquette = Mot     of string
               | Prefixe of string
;;

type arbre = Noeud of etiquette * (char * arbre) list ;;


(* char_list_of_string : string -> char list *)

let char_list_of_string s =
  let rec aux acc = function
      -1 -> acc
    | i  -> aux ((String.get s i)::acc) (pred i)
  in
  aux [] (String.length s - 1)
;;


(* string_of_char_list : char list -> string *)

let string_of_char_list cl =
  let n = List.length cl in
  let s = String.create n in
  let rec aux i = function
     []    -> s
    | c::l  -> String.set s i c ; aux (succ i) l
  in aux 0 cl
;;


(* change_assoc : ('a * 'b) list -> 'a -> 'b -> ('a * 'b) list *)

let change_assoc l a b =
  let rec change_rec = function
      []         -> []
    | (a',b')::l -> if a=a' then (a',b)::l else (a',b')::(change_rec l)
  in
  if List.mem_assoc a l then change_rec l else (a,b)::l
;;
 

(* insere_mot : arbre -> string -> arbre
 * Ajoute un mot dans un arbre pour donner un nouvel arbre. *)


let insere_mot arbre mot =
  let rec insere_rec chemin z e =
    match (z, e) with
      ((Noeud (Prefixe _,b)), []) -> Noeud (Mot mot, b)
    | (a, [])                     -> a
    | ((Noeud (e,b)), (c::l))     ->
        if List.mem_assoc c b then
          let fils = insere_rec (c::chemin) (List.assoc c b) l in
          Noeud (e, change_assoc b c fils)
        else
          let prefixe = string_of_char_list (List.rev (c::chemin)) in
          let fils = Noeud (Prefixe prefixe,[]) in
          Noeud (e, (c, insere_rec (c::chemin) fils l)::b)
           
  in insere_rec [] arbre (char_list_of_string mot)
;;


(* construit : string list -> arbre
 * Construit l'arbre correspondant à une liste de mots *)


let rec construit_arbre = function
    []   -> Noeud (Prefixe "",[])
  | m::l -> insere_mot (construit_arbre l) m
;;

(* Exemple : *)
let a = construit_arbre [ "caml" ; "cafe" ; "cafes" ; "java" ];;


(* descente  : arbre -> char list -> arbre
 * Descend dans un arbre le long d'une liste de caractères
 * et renvoie l'arbre où l'on est arrivé.
 * Lève une exception Failure "ce n'est pas un prefixe" si la liste
 * ne correspond pas à un chemin dans l'arbre. *)


let rec descente a l =
  match (a, l) with
    (a, [])                 -> a
  | ((Noeud (e,b)), (c::l)) ->
      if List.mem_assoc c b then
        descente (List.assoc c b) l
      else
        failwith "ce n'est pas un prefixe"
;;


(* complete : arbre -> string -> string
 * Trouve le plus grand complément dans l'arbre d'un mot donné *)


let complete a mot =
  let rec cherche_complement p = function
     [c, Noeud (Mot m,     b)] -> m
   | [c, Noeud (Prefixe _, b)] -> cherche_complement (c::p) b
   | _                         -> string_of_char_list (List.rev p)
  in
  match descente a (char_list_of_string mot) with
    (Noeud (Prefixe p,b)) -> cherche_complement (List.rev (char_list_of_string p)) b
  | (Noeud (Mot m,_))     -> m
;;

(* trouve_mots : arbre -> string list
 * Renvoie tous les mots contenus dans l'arbre *)


let applati l = List.fold_right (@) l [];;

let rec trouve_mots = function
    Noeud (Mot m,    b) -> m::(applati (List.map (fun (c,a) -> trouve_mots a) b))
  | Noeud (Prefixe _,b) -> (applati (List.map (fun (c,a) -> trouve_mots a) b))
;;


(* trouve_complements : arbre -> string -> string list
 * Trouve tous les mots de l'arbre dont p est un préfixe. *)


let trouve_complements a mot =
  let a' = descente a (char_list_of_string mot) in
  trouve_mots a'
;;


(**************************************************************************)
(*                              Optimisation                              *)
(**************************************************************************)

(* On optimise en notant sur chaque noeud le plus grand prefixe
 * pour un mot aboutissant sur ce noeud-la, au lieu de noter seulement
 * le mot sur lequel on est rendu. *)


let rec optimise a = match a with
    Noeud (Prefixe p, b) ->
        let p' = complete a "" in
        Noeud(Prefixe p', List.map (fun (c,f) -> c,optimise f) b)
  | Noeud (Mot m,     b) ->
        Noeud(Mot m, List.map (fun (c,f) -> c,optimise f) b)
;;

let rec complete_opt a mot =
  match descente a (char_list_of_string mot) with
     (Noeud (Prefixe m,_)) -> m
   | (Noeud (Mot m    ,_)) -> m
;;
 
Webmaster : pierrefrancois.leon@laposte.net

Valid XHTML 1.0 Strict Valid CSS!