Adloun

Probleme – Le tri rapide : pourquoi il gagne en moyenne et perd au pire

Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 15 — Diviser pour régner

Énoncé

Le cours signale que le tri rapide « dégénère en sur les pires entrées ». On regarde de près.

Corrigé

1. Le tri.


(* Trie t.[g .. d] en place. Précondition : 0 <= g, d < |t|.
   Complexité : Theta(n log n) en moyenne, Theta(n^2) au pire. *)
let echanger t i j = let x = t.(i) in t.(i) <- t.(j); t.(j) <- x

let rec trier t g d =
  if g < d then begin
    let pivot = t.(d) in
    let i = ref g in
    (* INVARIANT : t.[g .. i-1] <= pivot, et t.[i .. j-1] > pivot. *)
    for j = g to d - 1 do
      if t.(j) <= pivot then begin echanger t !i j; incr i end
    done;
    echanger t !i d;                (* le pivot prend sa place DÉFINITIVE *)
    trier t g (!i - 1);
    trier t (!i + 1) d
  end

Terminaison : variant ; le pivot étant placé définitivement, les deux appels portent sur des intervalles strictement plus courts. Correction : l'invariant garantit qu'après la boucle, tout ce qui est à gauche de est pivot et tout ce qui est à droite est ; le pivot y est donc à sa place finale, et il suffit de trier les deux côtés.

2. Le pire cas. C'est le tableau déjà trié : le pivot, pris en dernière position, est alors le maximum, la partition ne sépare rien, et l'on récurse sur éléments. D'où .

comparaisonsprofondeur
6464
256256

Le compte est exactement : le tri rapide devient un tri par sélection.

Et le second défaut est pire que le premier : la profondeur de récursion vaut . À , la pile d'exécution du chapitre chap:recursivite déborde, et le programme ne rend pas un mauvais résultat — il s'arrête. Le pire cas du tri rapide n'est pas une lenteur, c'est un plantage, et il survient sur l'entrée la plus banale qui soit : des données déjà en ordre.

3. La parade : le médian de trois. On prend pour pivot la médiane de , et , et on l'échange en position avant de partitionner.


let median3 t g d =
  let m = g + (d - g) / 2 in
  let a = t.(g) and b = t.(m) and c = t.(d) in
  if (a <= b && b <= c) || (c <= b && b <= a) then m
  else if (b <= a && a <= c) || (c <= a && a <= b) then g else d
tableau triétableau aléatoire
pivot = derniermédian de 3pivot = derniermédian de 3
(prof. ) (prof. 11)
(prof. ) (prof. 13)
------

Sur un tableau trié, le médian de trois choisit le vrai milieu : les partitions sont parfaites, la profondeur tombe à , et le coût à . Sur des données aléatoires, le gain n'est que de quelques pour cent — c'est normal, un pivot tiré au hasard y est déjà bon.

Mais le médian de trois ne supprime pas le pire cas, il le déplace : il existe des tableaux, construits exprès, qui le mettent en défaut. Les seules parades garanties sont le pivot tiré au hasard (chapitre chap:probabilistes) — dont le pire cas devient improbable au lieu d'impossible — ou le basculement sur un tri par tas au-delà d'une profondeur , ce que font les bibliothèques standard.

4. Pourquoi on l'emploie quand même. À nombre de comparaisons comparable — contre pour la fusion à —, le tri rapide gagne sur trois points que le comptage ne montre pas :

La complexité asymptotique départage les algorithmes ; elle ne les classe pas. Le tri par partition-fusion garde l'avantage quand la garantie compte plus que la moyenne, quand les données sont sur disque — la fusion lit séquentiellement, la partition non — et quand la stabilité est requise.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.