Travaux dirigés n o 6 Lycée Kléber MPSI, Option Info 2014/2015
Exercice 1 (Indexation d un arbre binaire) Ecrire une fonction Caml indexation : ( f, n) arbre_binaire -> (string,string) arbre_binaire qui remplace toute l information des nœuds et feuilles de l arbre fourni en argument par le mot binaire correspondant à l indexation décrite dans le cours. Exercice 2 (Sous-arbres de profondeur donnée) Ecrire une fonction Caml liste_a_profondeur : ( f, n) arbre_binaire -> int -> ( f, n) arbre_binaire list qui prend en arguments un arbre binaire a et un entier n et qui renvoie la liste (éventuellement vide) de tous les sous-arbres de a dont la racine est à la profondeur n dans a. Exercice 3 (Calcul du squelette) Ecrire une fonction Caml deshabille : ( f, n) arbre_binaire -> squelette
qui prend en argument un arbre binaire et qui renvoie son squelette. Exercice 4 (Tri par tas ou heapsort) 1 Ecrire une fonction : liste_aleatoire n qui rende une liste de n nombres entiers aléatoires. Utiliser la fonction : random int k qui rend un entier pseudo aléatoire entre 0 et k. 2 Ecrire une fonction : trinaif L qui trie une liste d entiers par ordre croissant : le principe est de trier la queue de la liste, puis d insérer le premier élément en bonne place grce une fonction insert_ds_liste_triee x liste. Le but du jeu est d écrire un tri efficace en utilisant la structure de données de tas (heap). Un tas est un arbre binaire, dont les nœuds portent des éléments (ici des entiers) d un ensemble complètement ordonné (ici N ). La valeur portée par tout nœud est inférieure (ou égale, mais pas supérieure) aux valeurs portées par le fils gauche et le fils droit. La valeur en un nœud est donc inférieure ou égale à
toutes les valeurs portées par les descendants de ce nœud. Exercice 5 Un tas est décrit par le type : type Tas= Rien Noeud of int * Tas * Tas;;. On aura besoin de deux fonctions, l une pour ajouter un élément (un entier) dans un tas, l autre pour amputer un tas de sa racine. 3 Pour amputer, écrire une fonction : enlever untas qui utilise le principe suivant : soit (x,fg,fd) le tas. La racine du nouveau tas portera le petit élément entre fg et fd ; supposons que ce soit l élément de fg ; alors le nouveau fils gauche est enlever fg, et le nouveau fils droit est fd. 4 Pour ajouter un élément y, écrire une fonction : ajouter y untas. C est trivial si le tas est vide. Sinon soit x la valeur de la racine. La racine du nouveau tas est le minimum de x et de y. Le fils gauche du nouveau tas est le fils droit de l ancien, et le fils droit du nouveau tas est le résultat de l ajout de max x y au fils gauche de l ancien tas.
Ainsi on insère toujours à droite, mais on permute fils gauche et droit à chaque descente. Ces permutations évitent d avoir un arbre plus lourd à droite qu à gauche. On pourrait bien sûr prendre la conversion symétrique (insérer systématiquement à gauche, en permutant gauche et droite lors de chaque descente). On pourrait aussi ne pas permuter gauche et droite, mais choisir aléatoirement à chaque insertion entre la gauche et la droite. Toutes ces techniques (dites de randomisation) font que le tas obtenu reste équilibré, même après de nombreuses insertions et suppressions. 5 Ecrire une fonction : najouter liste untas qui ajoute tous les éléments d une liste d entiers dans le tas. 6 Ecrire une fonction : vider untas qui rend la liste triée des éléments contenus dans le tas. Bien sûr, cette fonction appelle la fonction enlever définie précédemment. 7 Ecrire une fonction : tripartas liste qui trie une liste d entiers, en les insérant dans un tas, puis en vidant le tas (heapsort).
Comparer les temps d éxécution de cette fonction avec trinaif sur une longue liste (disons dix mille éléments). Exercice 6 ( extrait de CCP 2012) Un arbre binaire de recherche est un arbre binaire d entiers dont : les fils de la racine sont des arbres binaires de recherche ; les étiquettes de tous les nœuds composant le fils gauche de la racine sont inférieures ou égales à l étiquette de la racine ; les étiquettes de tous les nœuds composant le fils droit de la racine sont strictement supérieures à l étiquette de la racine. Un arbre binaire d entiers est représenté par le type arbre dont la définition est : type arbre = Vide Noeud of arbre * int * arbre;; Dessiner l arbre correspondant à :
Noeud( Noeud( Noeud( Noeud(Vide,1,Vide), 3, Noeud(Vide,4,Vide) ), 5, Vide), 7, Noeud( Noeud(Vide,8,Vide), 9, Vide) ) Est-ce un arbre de recherche? Exercice 7 Soit le programme en Karelle langage JULLIAN CaML TD: 6, arbres
let rec eliminer v a = let rec aux a = match a with Noeud(g,v,Vide) -> (v,g) Noeud(g,v,d) -> let (vr,ar) = (aux d) in (vr,(noeud(g,v,ar))) in match a with Vide -> Vide Noeud(g,vp,d) -> if (vp = v) then (let rg = (eliminer v g) in (if (rg = Vide) then d else let (vm,gp) = aux rg in Noeud(gp,vm,d))) else
if (v < vp) then Noeud((eliminer v g),vp,d) else Noeud(g,vp,(eliminer v d));; Soit la constante exemple définie et initialisée par : let exemple = Noeud(Noeud(Noeud(Vide,1,Vide),2,Vide),2,Noeud(Vide,3,Vide) Détailler les étapes du calcul de (eliminer 2 exemple) en précisant pour chaque appel aux fonctions eliminer et aux, les valeurs des paramètres et résultats.