Cours alternatif d’OCaml

Logo OCaml
IX — Les arbres

Entraînement

Cet entraînement est le dernier du cours, après vous saurez tout (ou presque) sur OCaml !

Prenons ce code :

type arbre =
  | Fin
  | Noeud of char * arbre * arbre

let a =
  Noeud(
    'k',
    Noeud(
      'g',
      Noeud(
        'f',
        Noeud('a', Fin, Fin),
        Fin
      ),
      Noeud('i', Fin, Fin)
    ),
    Noeud('k', Fin, Fin)
  )

N’hésitez pas à dessiner l’arbre a si ça vous aide.

Quelle est la taille de a ?

Quelle est la profondeur de a ?

Que vaut la racine de a ?

Combien a a-t-il de feuilles ?

On va passer à un exercice plus concret. Imaginons que vous conceviez une application pour gérer les relevés de notes de l’université. Lors de la remise des bulletins, vous devez associer à chaque numéro d’anonymat un nom d’étudiant·e. Mais il y a beaucoup d’étudiants, alors pour accélérer la recherche dans la liste, vous décidez de passer par un dictionnaire binaire.

Le fonctionnement est le même qu’un arbre binaire classique, mais on associe à chaque nœud un couple, qui sera ici de type int * string (numéro d’étudiant et nom). On classe les données dans l’arbre selon le numéro d’étudiant uniquement.

L’exercice est de créer le type dico_binaire et les fonctions ajouter (qui prend un arbre, un numéro et un nom) et trouver_nom (qui prend un arbre et un numéro) correspondantes.

Proposition de correction
type dico_binaire =
  | Fin
  | Noeud of (int * string) * dico_binaire * dico_binaire

let rec ajouter (num : int) (nom : string) (dic : dico_binaire) : dico_binaire =
  match dic with
  | Fin -> Noeud((num, nom), Fin, Fin)
  | Noeud((num_actuel, nom_actuel), gauche, droite) ->
    if num_actuel = num then (* Les deux numéros sont les mêmes : on met à jour le nom *)
      Noeud((num_actuel, nom), gauche, droite)
    else if num_actuel > num then (* On insère à gauche *)
      Noeud((num_actuel, nom_actuel), ajouter num nom gauche, droite)
    else (* On insère à droite *)
      Noeud((num_actuel, nom_actuel), gauche, ajouter num nom droite)

let rec trouver_nom (num : int) (dic : dico_binaire) : string =
  match dic with
  | Fin -> "Introuvable"
  | Noeud((n, nom), gauche, droite) ->
    if num = n then
      nom
    else if num < n then
      trouver_nom num gauche
    else
      trouver_nom num droite

Si vous voulez aller plus loin, essayez de rendre dico_binaire polymorphe (pour accepter autre chose que des entiers et du texte), et créez la fonction supprimer (dic : ('a, 'b) dico_binaire) (cle : 'a) : ('a, 'b) dico_binaire.

Si vous voulez vous entraîner à la démonstration par induction structurelle, essayer de prouver les propriétés suivantes :

  1. La profondeur d’un arbre binaire est inférieure à sa taille.
  2. La taille d’un arbre binaire est inférieure à 2 puissance : profondeur moins 1.

Et voilà, ce cours se termine ici. Si vous aimez bien OCaml et que vous voudriez aller plus loin, l’annexe C peut vous donner des pistes. Merci d’avoir lu jusqu’ici, j’espère que ce cours vous aura aidé (et on dit chocolatine).