Tri Rapide

publicité
L2S3 Harmonisation
UFR d'IEEA Université Lille 1
Algorithmique
20142015
TP : Tri Rapide
Dans ce TP vous pouvez utiliser le module Permutation donné sur le portail. Il fournit
les fonctions suivantes :
identite : int -> int array qui prend en paramètre un entier n et retourne un
tableau de taille n dont la case i contient l'entier i
melange : int array -> int array qui prend en paramètre un tableau d'entiers
et échange (pseudo-)aléatoirement ses cases
1
Principe
Le tri rapide, ou quicksort, est fondé comme le tri par fusion sur le paradigme "diviser
pour régner". C'est en eet également un algorithme récursif qui procède en divisant le
tableau en deux sous-tableaux, les tri (récursivement) et recombine les deux parties.
La diérence entre ces deux algorithmes de tri réside dans la manière de diviser le
tableau puis de recombiner. Contrairement au tri par fusion, l'étape la plus coûteuse du
tri rapide, donc celle où s'eectue tout le travail, est la division en deux sous tableaux.
La recombinaison et immédiate et ne nécessite aucun travail.
De plus le tri rapide est un tri "en place" ou "sur place" : un espace mémoire constant
en plus du tableau tableau à trier est susant pour eectuer ce tri.
De manière plus détaillée le principe du tri rapide est le suivant :
1.
Diviser/Partitionner :
2.
Trier :
3.
Recombiner :
2
Un élément du tableau est choisi arbitrairement, on appel
cet élément le pivot. La division consiste à placer tous les éléments de valeur inférieure à celle du pivot au début du tableau et tous les supérieurs en n de tableau.
Les éléments de valeur égale au pivot se trouvent au milieu. Le tableau est donc
divisé en trois parties : les éléments inférieurs, égaux puis supérieurs au pivot.
Il s'agit simplement de trier récursivement les deux parties contenant les
éléments inférieurs et supérieurs au pivot.
Rien à faire, le tableau est déjà trié !
Choix du pivot
Comme vous le verrez dans la suite du TP choisir une bonne valeur de pivot est très
important pour avoir la meilleur complexité possible. Cependant choisir le pivot optimal
à chaque appel récursif nécessite presque autant d'opérations que pour trier le tableau,
c'est pourquoi on choisit en général une valeur aléatoirement dans le tableau.
Ecrivez la fonction pivot retournant une valeur ( pas un indice !) choisie aléatoirement dans le tableau t entre les indices d et f , où t, d et f sont donnés en paramètre.
Q1 .
1
3
Partition
Il y a plusieurs méthodes pour écrire un algorithme itératif de partition, l'une d'elles
consiste à maintenir quatre zones délimitées par trois indices, a, b et c, comme illustré sur
la Figure 1 :
1. les éléments inférieurs au pivot se trouvent aux indices strictement inférieurs à a,
2. les éléments égaux au pivot se trouvent entre les indices a et c − 1,
3. les éléments supérieurs au pivot sont aux indices strictement supérieurs à b,
4. les éléments restant entre les indices c et b n'ont pas encore été comparés au pivot
et n'ont donc pas encore été placés dans l'une des trois précédentes parties.
a
< pivot
c
= pivot
b
???
> pivot
Figure 1 Partition
L'idée est de comparer l'élément d'indice c au pivot puis de l'insérer dans l'une des
trois parties, inférieur, supérieur ou égale au pivot, suivant sa valeur.
3.1
La fonction
partition
Donnez les conditions vériées par les indices a, b et c lorsque la partition est
terminée, c'est-à-dire lorsqu'il ne reste plus d'éléments qui n'ont pas été comparés au
pivot.
Q2 .
Quel est, en fonction de a, b et c, le plus grand indice x d'un élément strictement
inférieur au pivot à la n de l'algorithme de partition ?
Q3 .
Quel est, en fonction de a, b et c, le plus petit indice y d'un élément strictement
supérieur au pivot à la n de l'algorithme de partition ?
Q4 .
Q5 . Donnez les valeurs initiales des indices a, b et c en fonction des indices d et f de
début et n de tableau, c'est-à-dire lorsqu'aucun élément n'a encore été comparé au pivot.
Ecrivez la fonction partition qui partitionne selon valeur p du pivot les éléments
du tableau t compris entre les indices d et f en trois parties : éléments inférieurs, égaux et
supérieurs au pivot. Cette fonction prend en paramètre t, d, f et p et retourne le couple
(x,y ) d'indices où x est le plus grand indice d'un élément strictement inférieur au pivot
et y est le plus petit indice d'un élément supérieur au pivot à la n de l'algorithme de
paritionnement.
Q6 .
Quelle propriété intéressante pour des éléments au cours d'un algorithme de tri est
vériée par tous les éléments de valeur égale au pivot lorsque la partition est terminée ?
Q7 .
2
3.2
Complexité
L'algorithme a-t-il des cas pire ou meilleur que les autres en terme de nombre de
comparaisons eectuées entre le pivot et les autres éléments du tableau ? Si oui donnez
ces cas, sinon expliquez pourquoi.
Q8 .
Combien de comparaisons entre le pivot et les autres éléments du tableau t entre
les indices d et f sont eectuées ? Vous pouvez justier votre réponse par un argument
(convaincant) ou un calcul.
Q9 .
Q10 .
Donnez l'ordre de grandeur asymptotique du nombre de comparaisons.
3.3
Preuve de correction
Cette partie n'est pas obligatoire mais pas inintéressante non plus ...
Prouver qu'un algorithme est correct consiste simplement à montrer que le calcul ou
le traitement qu'il eectue est bien celui pour lequel il a été écrit : à partir de données
vériant ses conditions d'utilisation il conduira toujours à un état nal ou résultat qui
vérie une propriété attendue.
Une preuve de correction est partielle si elle montre seulement que si l'algorithme
s'arrête alors il est correct. Il faut dans ce cas si possible la compléter par une preuve de
terminaison, c'est-à-dire montrer que l'algorithme va eectivement s'arrêter.
La logique de Hoare permet à partir d'une propriété vraie en début d'algorithme,
comme une condition d'utilisation, de déduire des propriétés vériées à chaque étape,
c'est-à-dire entre chaque calculs élémentaires, puis en n de l'algorithme. Ecrire une preuve
compléte à la main est en général fastidieux.
Cependant la mise en évidence d'invariant de boucle permet souvent de se convaincre
qu'un algorithme itératif est correct. Un invariant de boucle est une propriété qui est
vériée après la phase d'initialisation, reste vraie à l'issue de chaque itération et qui
conjointement avec la condition d'arrêt de la boucle permet de montrer que le résultat
obtenu à la n de la boucle est bien celui qui est attendu.
Proposez un invariant (de boucle) pour (l'unique boucle de) l'algorithme de partitionnement.
Q11 .
Q12 .
Votre invariant est-il vrai au début de la première itération ?
Expliquer pourquoi si l'invariant est vérié en début d'une itération il sera toujours
vrai au début de l'itération suivante.
Q13 .
Q14 .
Donnez une preuve de correction informelle et partielle de l'algorithme.
En observant ce qu'il se passe à chaque itération, justiez que l'algorithme de
partionnement va bien se terminer.
Q15 .
4
Tri récursif
Toute la diculté du tri se trouve dans la partition du tableau et comme pour le
tri par fusion, une fois la partie délicate de l'algorithme encapsulée dans une fonction
3
(partition ici) l'algorithme récursif de tri ne prend plus que quelque lignes à écrire.
4.1
La procédure
tri_rapide
Ecrivez la procédure tri_rapide prenant en paramètre un tableau t et deux
indices d et f de début et n de tableau et qui eectue un tri rapide sur t. Vous pouvez
naturellement utiliser les fonctions pivot et partition écrites précédemment.
Q16 .
Justiez rapidement que l'algorithme eectue bien un tri du tableau. Vous pouvez
pour cela utiliser la propriété vériée par les éléments égaux à la valeur du pivot à la n
de la fonction partition.
Q17 .
4.2
Complexité
Donnez l'équation de récurrence décrivant le nombre de comparaisons entre éléments du tableau eectuées lors de l'exécution de la procédure tri_rapide sur un tableau
de taille n. Dans un premier temps on pourra considérer qu'il y a nI éléments inférieurs
et nS éléments supérieurs au pivot.
Dans la suite on supposera qu'une valeur n'apparaît qu'une seule fois dans le tableau
et donc qu'il ne peut pas y avoir plusieurs cases contenant une valeur égale au pivot.
Q18 .
Que devient l'équation de récurrence s'il y a toujours autant d'éléments inférieurs
que d'éléments supérieurs au pivot ?
Q19 .
Résoudre l'équation dans ce cas là et donner un ordre de grandeur asymptotique
du nombre de comparaisons que le tri eectue.
Q20 .
Que devient l'équation de récurrence si le pivot est toujours l'élément maximum
ou minimum du tableau ?
Q21 .
Résoudre l'équation dans ce cas là et donner un ordre de grandeur asymptotique
du nombre de comparaisons que le tri eectue.
Q22 .
Déduire de vos résultats précédents un pire et un meilleur cas pour l'algorithme
du tri rapide.
Q23 .
Q24 .
Le tri rapide est il intéressant pour un tableau presque trié ? Justiez votre réponse.
Remarque : La complexité en moyenne du tri rapide, c'est-à-dire la moyenne du
nombre d'opérations sur toutes les données possibles de taille n (= tous les tableau
possibles de taille n), est en Θ(n log n). En pratique ce tri est généralement plus ecace
que le tri par fusion dont la complexité est toujours en Θ(n log n).
4
Téléchargement