type trie = { words : string list ; branches : (int * trie) list }

let empty = { words = []; branches = [] }

(* recherche *)

let rec find trie = function
  | [] ->
      trie.words
  | i :: l ->
      begin
        try find (List.assoc i trie.branches) l
        with Not_found -> []
      end

(* ajout *)

let rec change_assoc i trie = function
  | [] -> [i,trie]
  | (x,_) :: l when x = i -> (i,trie) :: l
  | z :: l -> z :: change_assoc i trie l

let branch i t =
  try List.assoc i t.branches with Not_found -> empty

let add trie l s =
  let rec add trie = function
    | [] when List.mem s trie.words ->
        trie
    | [] ->
        { trie with words = s :: trie.words }
    | i :: l ->
        let t = branch i trie in
        { trie with branches = change_assoc i (add t l) trie.branches }
  in
  add trie l

(* ajout d'un mot *)

let key = function
  | 'a' | 'b' | 'c' -> 2
  | 'd' | 'e' | 'f' -> 3
  | 'g' | 'h' | 'i' -> 4
  | 'j' | 'k' | 'l' -> 5
  | 'm' | 'n' | 'o' -> 6
  | 'p' | 'q' | 'r' | 's' -> 7
  | 't' | 'u' | 'v' -> 8
  | 'w' | 'x' | 'y' | 'z' -> 9
  | _ -> assert false

let intlist_of_string s =
  let n = String.length s in
  let rec list i =
    if i = n then [] else key s.[i] :: list (i+1)
  in
  list 0

let add_word trie w = add trie (intlist_of_string w) w

(* un petit dictionnaire *)

let dict = [
  "lex"; "key"; "void" ; "caml" ; "unix" ; "for" ; "while" ; "done" ;
  "let" ; "fold";
  "val"; "exn" ; "rec" ; "else" ; "then" ; "type" ; "try" ; "with" ;
  "to"; "find" ; "do" ; "in" ; "if" ; "hd" ; "tl" ; "iter" ; "map" ; "get";
  "copy" ; "and"; "as" ; "begin" ; "class" ; "downto" ; "end" ;
  "exception" ; "false" ; "fun" ; "function" ; "match" ; "mod" ; "mutable" ;
  "open" ; "or" ; "true" ;  "when" ;  "load" ; "mem" ; "length" ; "bash" ;
  "unit" ; "site";
  "php"; "sql"; "ssh"; "spam"; "su"; "qt"; "root";
  "bsd"; "boot"; "caml"; "bash"; "ocaml"; "kde"; "gtk" ; "gcc"
]

let t = List.fold_left add_word empty dict

(* tests *)

let () = assert (find t [2;2;6;5] = ["caml"])
let () = assert (let l = find t [4;3] in l = ["hd"; "if"] || l = ["if"; "hd"])
let () = assert (find t [4;3;8]   = ["get"])
let () = assert (find t [8;6;4;3] = ["void"])
let () = assert (find t [8;6;4;8] = ["unit"])

(* suppression *)

let remove trie l s =
  let rec remove trie = function
    | [] ->
        { trie with words = List.filter ((<>) s) trie.words }
    | i :: l ->
        let t = branch i trie in
        let f = match remove t l with
          | { words=[]; branches=[] } -> List.remove_assoc i
          | t' -> change_assoc i t'
        in
        { trie with branches = f trie.branches }
  in
  remove trie l

let remove_word trie w = remove trie (intlist_of_string w) w

(* tests *)

let t = remove_word t "caml"
let () = assert (find t [2;2;6;5] = [])
let () = assert (let l = find t [4;3] in l = ["hd"; "if"] || l = ["if"; "hd"])
let () = assert (find t [4;3;8]   = ["get"])


This document was generated using caml2html