Skip to content
Snippets Groups Projects
tp3.ml 6.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • COQUERY EMMANUEL's avatar
    COQUERY EMMANUEL committed
    (* LIFPF TP3 Récursion sur les arbres *)
    
    (**********************************************************************)
    (* Arbres binaires *)
    (**********************************************************************)
    
    (**
    Arbres binaires avec feuilles vides, 
    le contenu est seulement sur les noeuds.    
    *)
    type arbre_bin = ABVide | ABNoeud of int * arbre_bin * arbre_bin
    
    (* Quelques arbres pour tester *)
    let ab1 = ABNoeud (3, ABVide, ABVide)
    let ab2 = ABNoeud (5, ab1, ABVide)
    let ab3 = ABNoeud (7, ABVide, ab1)
    let ab4 = ABNoeud (11, ab2, ab3)
    
    (**
    Taille d'un arbre binaire.
    @param a l'arbre dont on veut calculer la taille
    @return le nombre d'int stockés dans l'arbre
    *)
    let rec taille_ab (a : arbre_bin) : int =
      match a with
      | ABVide -> 0
      | ABNoeud (_, fg, fd) -> 1 + taille_ab fg + taille_ab fd
    ;;
    
    assert (taille_ab ab1 = 1);;
    assert (taille_ab ab2 = 2);;
    assert (taille_ab ab3 = 2);;
    assert (taille_ab ab4 = 5)
    
    (**
    Fait le produit des éléments d'un arbre binaire.
    Un arbre vide aura 1 comme produit   
    @param a l'arbre dont on veut faire le produit des éléments
    @return le produit (1 pour l'arbre vide)
    *)
    let rec produit_ab (a : arbre_bin) : int =
      match a with
      | ABVide -> 1
      | ABNoeud (n, fg, fd) -> n * produit_ab fg * produit_ab fd
    ;;
    
    assert (produit_ab ABVide = 1);;
    assert (produit_ab ab1 = 3);;
    assert (produit_ab ab2 = 15);;
    assert (produit_ab ab3 = 21);;
    assert (produit_ab ab4 = 3465)
    
    (**
    Construit la liste des éléments d'un arbre binaire. Les éléments sont produits
    dans l'ordre de parcours infix, c'est à dire les éléments du fils gauche puis
    l'élément du noeud puis ceux fils droit.
    
    @param a l'arbre binaire dont on veut les éléments 
    @return la liste des éléments de l'arbre
    *)
    let rec list_of_arbre_bin (a : arbre_bin) : int list =
      match a with
      | ABVide -> []
      | ABNoeud (n, fg, fd) ->
          (* On peut aussi utiliser la fonction concatene du TP2 *)
          list_of_arbre_bin fg @ (n :: list_of_arbre_bin fd)
    ;;
    
    assert (list_of_arbre_bin ABVide = []);;
    assert (list_of_arbre_bin ab1 = [ 3 ]);;
    assert (list_of_arbre_bin ab2 = [ 3; 5 ]);;
    assert (list_of_arbre_bin ab3 = [ 7; 3 ]);;
    assert (list_of_arbre_bin ab4 = [ 3; 5; 11; 7; 3 ])
    
    (**
    Insère un élément dans un arbre binaire de recherche.
    
    @param e l'élément à insérer
    @param a l'arbre dans lequel on fait l'insersion
    @return un arbre binaire de recherche contenant les éléments de a ainsi que e
    *)
    let rec insere_arbre_bin_recherche (e : int) (a : arbre_bin) : arbre_bin =
      match a with
      | ABVide -> ABNoeud (e, ABVide, ABVide)
      | ABNoeud (x, fg, fd) ->
          if e < x then ABNoeud (x, insere_arbre_bin_recherche e fg, fd)
          else ABNoeud (x, fg, insere_arbre_bin_recherche e fd)
    
    let abr1 = insere_arbre_bin_recherche 7 ABVide
    let abr2 = insere_arbre_bin_recherche 5 abr1
    let abr3 = insere_arbre_bin_recherche 3 abr2
    let abr4 = insere_arbre_bin_recherche 11 abr3;;
    
    assert (list_of_arbre_bin abr1 = [ 7 ]);;
    assert (list_of_arbre_bin abr2 = [ 5; 7 ]);;
    assert (list_of_arbre_bin abr3 = [ 3; 5; 7 ]);;
    assert (list_of_arbre_bin abr4 = [ 3; 5; 7; 11 ])
    
    (**
    Créée un arbre binaire de recherche contenant les éléments de la liste
    
    @param l la liste contenant les éléments à placer dans l'arbre à créer
    @return l'arbre binaire de recherche contenant les éléments de l
    *)
    let rec arbre_bin_rech_of_int_list (l : int list) : arbre_bin =
      match l with
      | [] -> ABVide
      | x :: l' -> insere_arbre_bin_recherche x (arbre_bin_rech_of_int_list l')
    ;;
    
    assert (list_of_arbre_bin (arbre_bin_rech_of_int_list []) = []);;
    assert (list_of_arbre_bin (arbre_bin_rech_of_int_list [ 3 ]) = [ 3 ]);;
    assert (list_of_arbre_bin (arbre_bin_rech_of_int_list [ 3; 5 ]) = [ 3; 5 ]);;
    assert (list_of_arbre_bin (arbre_bin_rech_of_int_list [ 5; 3 ]) = [ 3; 5 ]);;
    
    assert (
      list_of_arbre_bin (arbre_bin_rech_of_int_list [ 1; 2; 3; 4 ]) = [ 1; 2; 3; 4 ])
    ;;
    
    assert (
      list_of_arbre_bin (arbre_bin_rech_of_int_list [ 4; 2; 1; 3 ]) = [ 1; 2; 3; 4 ])
    
    (**
    Trie une list d'int en utilisant un arbre binaire de recherche
    
    @param l la liste à trier
    @return la liste triée
    *)
    let tri_abr (l : int list) : int list =
      list_of_arbre_bin (arbre_bin_rech_of_int_list l)
    ;;
    
    assert (tri_abr [] = []);;
    assert (tri_abr [ 3 ] = [ 3 ]);;
    assert (tri_abr [ 3; 5 ] = [ 3; 5 ]);;
    assert (tri_abr [ 5; 3 ] = [ 3; 5 ]);;
    assert (tri_abr [ 1; 2; 3; 4 ] = [ 1; 2; 3; 4 ]);;
    assert (tri_abr [ 4; 2; 1; 3 ] = [ 1; 2; 3; 4 ])
    
    (**********************************************************************)
    (* Expressions arithmétiques et variables *)
    (**********************************************************************)
    
    (**
    Type représentant les opérateurs binaires.    
    *)
    type binop = Plus | Moins | Mult | Div
    
    (**
    Expressions arithmétiques + let    
    *)
    type expr =
      | Cst of int
      | Binop of binop * expr * expr
      | Var of string
      | Let of string * expr * expr
    
    (** affichage **)
    let rec string_of_expr (e : expr) : string =
      let string_of_binop (b : binop) =
        match b with Plus -> " + " | Moins -> " - " | Mult -> " * " | Div -> " / "
      in
    
      match e with
      | Cst n -> string_of_int n
      | Binop (op, l, r) ->
          "(" ^ string_of_expr l ^ string_of_binop op ^ string_of_expr r ^ ")"
      | Var x -> x
      | Let (v, e1, e2) ->
          "(let " ^ v ^ " = " ^ string_of_expr e1 ^ " in " ^ string_of_expr e2 ^ ")"
    
    (** Erreurs *)
    type eval_err = DivZero | VarNonDef
    
    (** Résultats: int ou erreur *)
    type resultat = Ok of int | Err of eval_err
    
    (**
    Évalue une expression dans un environnement
    *)
    let rec eval_expr (e : expr) (env : (string * int) list) : resultat =
      match e with
      | Cst n -> Ok n
      | Binop (op, e1, e2) -> (
          match (eval_expr e1 env, eval_expr e2 env) with
          | Ok v1, Ok v2 -> (
              match op with
              | Plus -> Ok (v1 + v2)
              | Moins -> Ok (v1 - v2)
              | Mult -> Ok (v1 * v2)
              | Div -> if v2 = 0 then Err DivZero else Ok (v1 / v2))
          | Err e, _ -> Err e
          | _, Err e -> Err e)
      | Var x -> (
          match List.assoc_opt x env with None -> Err VarNonDef | Some n -> Ok n)
      | Let (x, e1, e2) -> (
          match eval_expr e1 env with
          | Ok v1 -> eval_expr e2 ((x, v1) :: env)
          | Err e -> Err e)
    
    let e1 = Cst 3
    let e2 = Binop (Plus, Cst 3, Cst 5)
    let e3 = Binop (Div, Cst 3, Cst 0)
    let e4 = Let ("a", Cst 3, Binop (Moins, Var "a", Cst 3))
    let e5 = Let ("a", Cst 3, Var "b");;
    
    assert (eval_expr e1 [] = Ok 3);;
    assert (eval_expr e2 [] = Ok 8);;
    assert (eval_expr e3 [] = Err DivZero);;
    assert (eval_expr e4 [] = Ok 0);;
    assert (eval_expr e5 [] = Err VarNonDef);;
    assert (eval_expr e5 [ ("b", 11) ] = Ok 11)
    
    (**********************************************************************)