Révisions et structures de données

publicité
Lycée Carnot — 2016-2017
Option informatique MP/MP*
TD 1 : Révisions et structures de données
1
Remise en route
E XERCICE 1 (Typage) Quel est le type des fonctions suivantes ?
let
let
let
let
let
let
let
let
let
f1
f2
f3
f4
f5
f6
f7
f8
f9
x
m
l
x
x
x
x
x
=
= let y = !x + 1 in y;;
n = if n = m then m else n;;
= match l with [] -> [] | y :: s -> [s];;
y = for i = x to 10 do y := x :: !y done; !y;;
y = x y;;
y = x (x y);;
y = x (y x);;
y z = x y z;;
fun (x, y, z) -> fun x -> (x, y, z);;
E XERCICE 2 (Prévoir le résultat) Dans le programme suivant :
let
let
let
let
f
g
h
a
=
=
=
=
fun u -> (u 4) / 5;;
fun v -> fun x -> v (fun y -> x + y) + x;;
g f;;
h 11;;
Que vaut a ?
E XERCICE 3 (Currification) Quelle est la signature des deux fonctions suivantes ?
let add1(x, y) = x + y;;
let add2 x y = x + y;;
Ajouter les parenthèses implicites. On dit que la deuxième fonction est sous forme curryfiée. Expliquer
la différence d’approche et les avantages et inconvénients de ces deux choix possibles.
Écrire une fonction uncurry qui prend en argument une fonction curryfiée à deux arguments et retourne la même fonction non curryfiée, ainsi que sa réciproque curry. Quels sont leurs types ?
E XERCICE 4 (Sur les listes)
1. Réécrire la fonction list__map, de type (’a -> ’b) -> ’a list -> ’b list, qui renvoie
une liste constituée du résultat de l’appel d’une fonction sur chacun des éléments d’une liste.
2. On cherche à écrire l’équivalent de l’opérateur @ :
(a) Écrire une fonction rev_append de type ’a list -> ’a list -> ’a list telle que rev_append
l1 l2 renvoie le renversement de l1 concaténé avec l2. Cette fonction est-elle récursive terminale ? Quelle est sa complexité ?
(b) En déduire une fonction rev : ’a list -> ’a list
(c) En déduire une fonction append : ’a list -> ’a list -> ’a list qui concatène deux
listes. Quelle est sa complexité ? À votre avis, quel est son avantage par rapport à @ ?
3. Écrire le tri par insertion sur une liste.
E XERCICE 5
Le problème de la vache égarée
Une vache distraite se retrouve par mégarde dans le mauvais champs. Une clôture infinie s’étend devant elle et impossible de se souvenir si le passage se trouve à droite où à gauche.
http://carnot.cpge.info
1
Lycée Carnot — 2016-2017
Option informatique MP/MP*
1. La vache se souvient qu’elle a fait au plus n ∈ N pas entre sa position et le passage à travers la
clôture. Donner un algorithme en temps linéaire qui permet à la vache de retrouver le passage pour
aller de l’autre côté. Calculer la constante multiplicative et montrer que cet algorithme est optimal.
2. La vache ne se souvient en fait pas du tout du nombre de pas qui la sépare de l’ouverture. Peut-on
toujours trouver un algorithme en temps linéaire ? Si oui, calculer la constante multiplicative.
2
Structures de données
type ’a mstack;;
exception StackEmpty;;
exception StackFull;;
value
value
value
value
value
empty : unit -> ’a mstack;;
is_empty : ’a mstack -> bool;;
is_full : ’a mstack -> bool;;
push : ’a -> ’a mstack -> unit;;
pop : ’a mstack -> ’a ;;
F IGURE 1 – Signature pour une file impérative.
E XERCICE 6
Implémentation d’une file à l’aide de listes circulaires
L’année dernière et en TP vous avez implémenté une file impérative (modifiable) à l’aide d’un tableau
et de deux indices. Dans cet exercice on propose d’utiliser plutôt une liste chaînée circulaire, c’est-à-dire
que le dernier élément de la liste pointe sur le premier. Pour pouvoir insérer et extraire en temps constant,
il suffit de conserver un pointeur sur le dernier élément de la liste. La signature d’une file impérative est
rappelée à la figure 1.
1. Faire un dessin.
2. Implémenter la structure de file à l’aide d’une liste chaînée circulaire.
3. Quelle est la complexité des différentes opérations ?
E XERCICE 7
Files de priorité
Dans cet exercice on se propose d’implémenter la structure de file de priorité. Dans une file de priorité,
les éléments sont retirés non pas en fonction de leur ordre d’arrivée, mais en fonction d’une valeur attachée,
appelée priorité. Pour simplifier on suppose que la priorité est représentée par un entier. Une signature pour
une file de priorité persistante est donnée à la figure 2.
type ’a pprio;;
exception PrioEmpty;;
value
value
value
value
value
empty : ’a pprio;;
is_empty : ’a pprio -> bool;;
add : ’a -> int -> ’a pprio -> ’a pprio;;
get_min : ’a pprio -> ’a * int;;
remove_min : ’a pprio -> ’a pprio;;
F IGURE 2 – Signature pour une file de priorité persistante.
http://carnot.cpge.info
2
Lycée Carnot — 2016-2017
Option informatique MP/MP*
1. Donner des exemples de files de priorité et de leurs applications.
2. Au vu de la signature de la structure de données, que font les différentes opérations ?
3. Expliquer comment implémenter une pile et une file si l’on dispose d’une file de priorité.
4. On propose d’implémenter cette structure de données à l’aide d’un tas-min. On défini alors
type ’a pprio = Empty | ’a pprio * ’a * int * ’a pprio;;
5. Implémenter les fonctions empty, is_empty et get_min.
6. On suppose disposer d’une fonction merge : ’a pprio -> ’a pprio -> ’a pprio qui fusionne deux tas. Implémenter les opérations add et remove_min.
7. Implémenter la fonction merge. On ne cherchera pas à équilibrer les arbres.
8. Proposer la signature pour une file de priorité impérative. On pourra ajouter une exception dans le
cas où la file est pleine et un opérateur is_full. Ceci n’est bien sûr pas lié à l’aspect modifiable mais
au fait que nous allons utiliser un tableau (non redimensionnable).
9. Pour réaliser la version impérative on propose toujours d’utiliser un tas-min, mais on représente
celui-ci à l’aide d’un tableau. La racine de l’arbre occupe la case d’indice 0. Les racines des sousarbres du nœud stocké à la case i sont stockées respectivements aux cases 2i + 1 et 2i + 2. Où est
stocké le père du nœud i ?
10. Proposer un type ’a mprio utilisant un tas-min représenté dans un tableau. Implémenter les opérations empty, is_empty, is_full et get_min.
11. Écrire une fonction récursive percolate_up : ’a mprio -> ’a -> int -> int -> unit
telle que percolate_up p elt prio i insère l’élément elt de priorité prio dans un tas p en
partant de la position i. Cette fonction suppose que l’arbre de racine i obtenu en plaçant elt en i
est un tas.
12. En déduire une implémentation de l’opération add.
13. Écrire une fonction récursive percolate_down : ’a mprio -> ’a -> int -> int -> unit
telle que percolate_down p elt prio i insère l’élément elt de priorité prio dans le tas p, à
la place de l’élément en position i.
14. Implémenter l’opération remove_min. On pourra insérer à la racine l’élément le plus à droite du tas.
15. Quelle est la complexité des différentes opérations ?
E XERCICE 8
Arbres binomiaux
Pour k ∈ N, un arbre binomial Bk est un arbre ordonné (la liste des fils est ordonnée) défini récursivement
par : (a) B0 est constitué d’un nœud unique ; (b) pour k ≥ 1, Bk est l’arbre Bk−1 auquel on a rajouté comme
fils le plus à gauche un autre arbre Bk−1 .
1. Dessiner les arbres Bk pour 0 ≤ k ≤ 4.
2. Montrer qu’un arbre binomial Bk est constitué de 2k nœuds.
3. Montrer que sa hauteur est k.
4. Pour 0 ≤ i ≤ k, montrer qu’il existe exactement (ki) noeuds de profondeur i.
5. Montrer que la racine a pour degré k, et que ce degré est supérieur à celui des autres nœuds. Montrer
que les fils de Bk sont, dans l’ordre : Bk−1 , Bk−2 , . . . , B0 .
6. Montrer que le degré maximal d’un nœud quelconque dans un arbre binomial à n nœuds est log2 n.
http://carnot.cpge.info
3
Téléchargement