Petites questions¶
Exercice
- Écrire une fonction
somme
pour calculer la somme des éléments d'un tableau d'entiers. - Écrire une fonction
maximum
pour calculer le maximum d'un tableau d'entiers. On pourra utiliser la fonctionmax
renvoyant le maximum de 2 nombres. - Écrire une fonction
list_of_array
transformant un tableau en liste. - Tester si un tableau est trié par ordre croissant.
Solution
(* 1 *)
let somme t =
let res = ref 0 in
for i=0 to Array.length t - 1 do
res := !res + t.(i)
done;
!res in
somme [|3; 1; 7|];;
(* 2 *)
let maximum t =
let m = ref t.(0) in
for i=1 to Array.length t - 1 do
m := max t.(i) !m
done;
!m;;
maximum [|3; 1; 7|];;
(* 3 *)
let list_of_array t =
let rec aux i = (* transforme t.(0), ..., t.(i) en liste *)
if i = -1 then []
else t.(i)::aux (i - 1) in
aux (Array.length t - 1);;
list_of_array [|4; 3; 9; 1|];;
(* 4 *)
let croissant t =
let res = ref true in
for i=0 to Array.length t - 2 do
if t.(i) > t.(i + 1)
then res := false
done;
!res;;
- : int = 11
val maximum : 'a array -> 'a = <fun>
- : int = 7
val list_of_array : 'a array -> 'a list = <fun>
- : int list = [1; 9; 3; 4]
val croissant : 'a array -> bool = <fun>
Maximum local dans un tableau¶
Exercice
Un maximum local dans un tableau t
est un indice i
tel que t.(i) >= t.(i+1)
et t.(i) >= t.(i-1)
. Pour les extrémités, qu'une seule de ces conditions doit être vérifiée (si t.(i-1)
ou t.(i+1)
n'existe pas).
- Montrer qu'il existe forcément un minimum local dans
t
. - Écrire une fonction
max_local1
trouvant un maximum local dans un tableau en regardant chaque élément un par un (recherche séquentielle). Quelle est sa complexité ? - Écrire une fonction
max_local2
faisant la même chose mais avec une méthode par dichotomie (en divisant par 2 la taille du problème à chaque itération), pour avoir une complexité logarithmique.
Aide : soitt.(m)
le milieu du tableau. Que peut-on dire sit.(m) < t.(m+1)
? Sit.(m) < t.(m-1)
?
Solution
- Soit
t.(k)
le maximum det
. Alorsk
est un maximum local. Par contre il n'est pas forcément unique : par exemple dans[|1; 3; 2; 4|]
, les indices 1 (correspondant àt.(1) = 3
) et 3 (correspondant àt.(3) = 4
).
Solution
(* 2 *)
let max_local1 t =
let k = ref (-1) in (* on demande l'indice d'un minimum local *)
let n = Array.length t in
if t.(0) >= t.(1) then k := 0;
if t.(n - 1) >= t.(n - 2) then k := n - 1;
for i=1 to Array.length t - 2 do (* complexité O(n) où n est la taille de t, à cause de cette boucle *)
if t.(i) >= max t.(i + 1) t.(i - 1)
then k := i
done;
!k in
max_local1 [|1; 3; 5; 2|];;
(* 3 *)
(* On regarde le milieu t.(m) de t.
Si t.(m) >= max t.(m - 1) t.(m + 1) alors m est un maximum local
Si t.(m) < t.(m - 1) alors t a un maximum local à gauche de m. En effet soit t.(i) un maximum de t.(0), ... t.(m). Alors i est différent de m (car t.(m) < t.(m - 1)) donc est un maximum local.
Si t.(m) < t.(m + 1) alors, de même, t a un maximum local à droite de m. *)
let max_local2 t =
let n = Array.length t in
let rec aux i j = (* cherche un max local entre les indices i et j de t *)
let m = (i + j)/2 in
if (m = 0 || t.(m) >= t.(m-1)) && (m = n - 1 || t.(m) >= t.(m+1))
then m (* m est un max local *)
else if t.(m) < t.(m - 1) then aux i (m - 1)
else aux (m + 1) j in
aux 0 (n - 1);;
max_local2 [|1; 3; 5; 2|]
- : int = 2
val max_local2 : 'a array -> int = <fun>
- : int = 2
Tri par comptage¶
Exercice
Écrire une fonction tri_comptage : ’a array -> unit
qui trie un tableau t
de taille $n$ dont les entrées sont des entiers entre 0
et $M$ (où $M$ est le maximum de t
), en complexité O($n + M$).
Pour cela :
- Créer un autre tableau
compte
de taille $M + 1$ (avecArray.make
), initialement rempli de 0 - Remplir
compte
pour quecompte.(i)
contienne le nombre d'apparitions dei
danst
- Recopier les éléments de
compte
danst
dans l'ordre croissant pour obtenir un tableau trié
Solution
let tri_comptage t =
let m = maximum t in
let compte = Array.make (m+1) 0 in
let n = Array.length t in
for i=0 to n - 1 do
compte.(t.(i)) <- compte.(t.(i)) + 1
done;
let k = ref 0 in (* k est la position où on va ajouter le prochain élément dans t *)
for i=0 to m do
for j=1 to compte.(i) do
t.(!k) <- i;
incr k
done
done;; (* pas besoin de renvoyer un tableau car on modifie t en dehors de la fonction *)
let t = [|1; 9; 5; 3; 4|] in
tri_comptage t;
t
val tri_comptage : int array -> unit = <fun>
- : int array = [|1; 3; 4; 5; 9|]
Tranche maximum¶
Exercice
Écrire une fonction tranche_max : int array -> int
qui renvoie en O($n$) la somme maximum d'éléments consécutifs d'un tableau de taille $n$. Par exemple, tranche_max [|1; -2; 6; -3; 2; 4; -8; 7|]
doit renvoyer $9$, correspondant aux éléments 6; -3; 2; 4.
Indice : parcourir le tableau t
avec une boucle for. Stocker 2 variables m
et m_cur
telles que, au $i$ème passage dans la boucle for :
m
contient la somme maximum d'éléments consécutifs parmi les $i$ premiers éléments du tableaum_cur
contient la somme maximum d'éléments consécutifs finissant ent.(i)
.
Par exemple, lorsquetranche_max [|1; -2; 6; -3; 2; 4; -8; 7|]
exécute la $3$ème itération de la bouclefor
(c'est à dire que -3 est considéré),m
contient 6 (correspondant au seul élément 6) etm_cur
contient 3 (correspondant à 6; -3).
Solution
let tranche_max t =
let m = ref t.(0) in
let m_cur = ref t.(0) in
for i = 1 to Array.length t - 1 do
m_cur := max (!m_cur + t.(i)) t.(i);
m := max !m !m_cur
done;
!m;;
tranche_max [|1; -2; 6; -3; 2; 4; -8; 7|]
val tranche_max : int array -> int = <fun>
- : int = 9
Inversions dans un tableau¶
Exercice
Étant donné un tableau t
, une inversion de t
est un couple d'indices $(i, j)$ tels que $i < j$ et t
.$(i)$ > t
.$(j)$. Par exemple, [|4; 1; 5; 2|]
possède 3 inversions: $(0, 1)$, $(0, 3)$ et $(2, 3)$.
- Écrire une fonction
inv
en O($n^2$) déterminant le nombre d'inversions d'un tableau de taille $n$. Justifier que la complexité est bien O$(n^2$). - Écrire une fonction
inv_triee
telle que, sit1
ett2
sont deux tableaux triés par ordre croissant,inv_triee t1 t2
renvoie le nombre de couples $(i, j)$ tels quet1.(i) > t2.(j)
. La complexité deinv_triee
doit être linéaire en le nombre total d'éléments det1
ett2
. - (Difficile) Écrire une fonction
inv2
telle que, sit
est un tableau de taille $n$,inv2 t
renvoie le nombre d'inversions det
en complexité O($n\log(n)$).
On modifiera le tri fusion pour renvoyer le nombre d'inversions en plus de la liste triée.
Solution
(* 1 *)
let inv t =
let res = ref 0 in
let n = Array.length t in
for i=0 to n - 1 do (* répété n fois *)
for j=i+1 to n - 1 do (* répété au plus n fois *)
if t.(i) > t.(j) then res := !res + 1 (* répété au plus n² fois, donc complexité O(n²) *)
done
done;
!res;;
inv [|4; 1; 3; 2|];; (* test *)
val inv : 'a array -> int = <fun>
- : int = 4