Module LI213 – Types et Structures de données année 2004–2005 Examen de septembre du module LI213 Durée : 2 heures Seuls documents autorisés : le manuel de référence d’OCaml et vos notes manuscrites de cours et de TD Note importante : Si vous ne savez pas répondre à une question, supposez définie la fonction demandée pour les questions suivantes. Exercice 1 (6 points) Q 1.1 (1 point) Écrivez une fonction mem : ’a -> ’a list -> bool telle que mem e liste renvoie un booléen indiquant si e appartient à la liste. Q 1.2 (1 point) Écrivez une fonction unique : ’a list -> ’a list telle que unique l supprime les occurrences multiples de la liste l et retourne la liste résultante. L’ordre des éléments dans la liste retournée n’a aucune importance. Par exemple, unique [3 ; 4 ; 5 ; 4 ; 2 ; 3 ; 1] pourra retourner [5 ; 4 ; 2 ; 3 ; 1]. Q 1.3 (1 point) Écrivez une fonction intersect : ’a list -> ’a list -> ’a list telle que intersect l1 l2 renvoie la liste constituée uniquement des éléments appartenant à la fois à l1 et l2. Ces éléments ne doivent apparaı̂tre qu’une fois dans la liste re- page 2 Module LI213 – Types et Structures de données tournée. Par exemple, intersect [1 ;3 ;2 ;3 ;4] [2 ;3 ;5 ;2] renverra la liste [2 ;3] ou [3 ;2]. L’ordre des éléments dans la liste retournée n’a aucune importance. Q 1.4 (1 point) Écrivez une fonction union : ’a list -> ’a list -> ’a list qui renvoie l’union de deux listes, c’est-à-dire les éléments apparaissant dans au moins une des deux listes. Ceux-ci ne doivent apparaı̂tre qu’une fois dans la liste retournée et leur ordre dans cette liste n’a aucune importance. Q 1.5 (2 point) Écrivez une fonction elts : ’a list list -> ’a list qui prend en argument une liste de listes et qui renvoie la liste des éléments qui composent ces listes. Ceux-ci ne doivent apparaı̂tre qu’une fois dans la liste retournée et leur ordre dans cette liste n’a aucune importance. Par exemple, elts [[1 ;3 ;3 ;2] ; [2 ;4 ;5] ; [5]] pourra renvoyer [1 ; 3 ; 2 ; 4 ; 5]. Exercice 2 (6 points) On représente des polynômes par la liste de leurs coefficients (ordonnés selon les puissances croissantes dans le polynôme). Attention : tout au long de l’exercice, les listes sont telles que leur dernier entier (le coefficient de la plus grande puissance) est différent de 0. Ainsi, la liste [3 ;0 ;5 ;0 ;4 ;6] représente-t-elle le polynôme 3 + 5x2 + 4x4 + 6x5 et la liste [] le polynôme 0. Module LI213 – Types et Structures de données page 3 Q 2.1 (3 points) Écrivez une fonction add : int list -> int list -> int list telle que add p1 p2 renvoie la liste correspondant au polynôme p1 + p2. Rappelez-vous que les derniers éléments de la liste correspondant à p1 + p2 doivent être différents de 0. Ainsi add [1 ; 0 ; 3] [-1 ; 2 ; -3] renverra la liste [0 ; 2]. Q 2.2 (1 point) Écrivez une fonction scalar : int -> int list -> int list telle que scalar n p renvoie le produit du polynôme p par le scalaire n, autrement dit les coeffcients de p sont multipliés par n. N’oubliez pas que les derniers entiers de la liste retournée doivent être différents de 0. Q 2.3 (2 points) Écrivez une fonction valeur : int list -> int -> int telle que valeur p x renvoie la valeur du polynôme p au point x, c’est-à-dire p(x). Exercice 3 (8 points) Dans cet exercice, on utilise une structure d’arbre n-aire pour manipuler des intervalles. Chaque nœud de l’arbre représente un intervalle [x, y] où x et y sont des entiers. Les fils d’un nœud correspondent à des intervalles inclus dans celui-ci. De plus, l’arbre est construit de telle sorte que tous les fils d’un nœud représentent des intervalles disjoints deux à deux. La figure 1 représente un tel arbre. Pour représenter cet arbre en ocaml, on utilise les types nœud et arbre ci-dessous : type noeud = { intervalle : int * int; children : noeud list } and arbre = Nil | Elt of noeud;; page 4 Module LI213 – Types et Structures de données a [0,100] b [10,30] e [16,30] c [40,50] d [60,61] f [10,15] Fig. 1 – L’arbre d’intervalles emboités. Ainsi l’arbre de la figure 1 sera-t-il représenté de la manière suivante : let arbre = let noeud_c = {intervalle = (40,50); children = []} and noeud_d = {intervalle = (60,61); children = []} and noeud_e = {intervalle = (16,30); children = []} and noeud_f = {intervalle = (10,15); children = []} in let noeud_b = {intervalle = (10,30); children = [noeud_e; noeud_f]} in let noeud_a = {intervalle = (0,100); children = [noeud_b; noeud_c; noeud_d]} in Elt noeud_a;; Module LI213 – Types et Structures de données page 5 Q 3.1 (2 point) Soit la déclaration : type intersection = EMPTYSET | SUBSET | SUPSET | INTERSECT ; ; Écrivez une fonction : inter : ’a * ’a -> ’a * ’a -> intersection telle que inter (x,y) (z,t) renvoie : EMPTYSET si [x, y] ∩ [z, t] = ∅, SUBSET si [x, y] ⊆ [z, t], si [x, y] ⊃ [z, t], SUPSET INTERSECT sinon. Q 3.2 (2 points) Écrivez une fonction find list container : int * int -> noeud list -> arbre prenant en argument un intervalle [x, y] ainsi qu’une liste de nœuds/intervalles disjoints. S’il existe un nœud contenant l’intervalle [x, y] dans la liste, la fonction renvoie un arbre dont la racine est ce nœud. Sinon s’il existe un nœud représentant un intervalle [z, t] d’intersection non vide avec [x, y] et tel qu’aucun des deux intervalles [x, y] et [z, t] n’est inclus dans l’autre, alors la fonction lève une exception Intervalle error. Dans tous les autres cas, elle renvoie Nil. Ainsi : find list container (45,46) [noeud b ; noeud c ; noeud d] renverra Elt noeud c, find list container (30,46) [noeud b ; noeud c ; noeud d] lèvera l’exception : Intervalle error et l’application : find list container (55, 58) [noeud b ; noeud c ; noeud d] renverra Nil. Q 3.3 (4 points) Dans cette question, on recherche le nœud de l’arbre en dessous duquel page 6 Module LI213 – Types et Structures de données on pourrait insérer un nouvel intervalle [x, y]. Écrivez une fonction find container : int * int -> arbre -> arbre telle que find container (x,y) ab lève une exception s’il existe dans l’arbre un nœud représentant un intervalle [z, t] d’intersection non vide avec [x, y] et tel qu’aucun des deux intervalles [x, y] et [z, t] n’est inclus dans l’autre. Dans le cas contraire, elle renvoie le sous-arbre dont la racine est le nœud représentant le plus petit intervalle de l’arbre contenant [x, y] si celui-ci existe, et Nil sinon. Ainsi, find container (10,11) arbre renverra Elt noeud f, find container (10,28) arbre lèvera l’exception Intervalle error (car l’insertion de [10, 28] induirait que les fils de noeud b ne seraient pas disjoints) et find container (110,200) arbre renverra Nil.