Tri rapide - TSI Ljf.html

publicité
Informatique
Cours 4.2
Tri rapide (quick sort)
La méthode de tri rapide est basée sur la division de liste en 2 parties non égales à priori (algorithme du
type "diviser pour régner").
1 Principe du tri rapide (quick sort)
On applique la méthode diviser pour régner :
- On choisit un élément pivot p (1 er élément de la liste par exemple)
- On sépare les éléments du tableau t en deux groupes (pas nécessairement de même taille).
o G1 = les éléments x ≤ p.
o G2 = les éléments x > p.
- On place p dans sa position définitive : t = [G1 , p, G2]
- On répète ensuite récursivement les opérations précédentes à chaque groupe d’éléments
généré,
- A la fin des appels récursifs, le tableau t est trié.
Figure 1 : principe du tri rapide avec pivot choisi en 1ère position de liste.
Remarque : le pivot peut être le 1er élément, le dernier, la médiane ou une valeur aléatoire (mais la
recherche du pivot optimal peut générer plus d'instructions qu'il n'en fait économiser).
Lycée Jules Ferry Cannes
Page 1 sur 4
TSI2
Informatique
Cours 4.2
Tri rapide (quick sort)
2 Tri rapide en place
Le tri rapide peut être effectué en place en utilisant un indice m qui indique la place finale du pivot et
donc l'indice du dernier élément de G1 (borne exclus) et l'indice du début des éléments du groupe G2
(borne exclus).
Exemple avec une séquence entre i et j (on prend i=0 pour simplifier les écritures mais cela fonctionne
de la même façon pour toute valeur de i si on prend comme valeur initiale m = i et k=i+1 où k est l'indice
d'un élément du tableau hors pivot placé en i) :
Initialisation
m=i =0;
pivot enT[i] : p=5
k=1
5
8
m=0
k=1
5
8
j=5
3
pivot (gris foncé)
Première itération (k=1)
T[1]=8>p=5
m=1
échange T[m] et T[k]
m =2
5
5
5
5
9
2
9
élément G2
k=2
3
m=1
k=2
3
8
2
m=2
k=3
8
2
m=2
k=3
2
8
3
3
4e itération (k=4)
élément G1 (à échanger)
m=2
5
T[k]=9>p=5
2
8
i=0
échange T[m] et T[k]
3
m=1
3e itération (k=3)
T[k]=2≤p=5
9
éléments à grouper (blanc)
2e itération (k=2)
T[k]=3≤p=5
2
Placement du pivot
i=0
échange T[0] et T[m]
2
G1 (à resegmenter)
3
2
5
9
9
k=4
8
m=2
3
9
9
k=4
8
pivot (trié)
j=5
9
G2 (à resegmenter)
Figure 2 : é volution du tri pour l'algorithme de partition du tableau (pivot à gauche).
Lycée Jules Ferry Cannes
Page 2 sur 4
TSI2
Informatique
Cours 4.2
Tri rapide (quick sort)
3 Algorithme
L'algorithme de segmentation est le suivant.
Données :
T : un tableau de valeurs numériques [0..n-1]
i, j : les indices de début et de fin de la segmentation à effectuer (j exclus)
Résultat : le tableau T « segmenté » avec le pivot à sa place définitive, l’indice de la place du pivot
Segmenter(T,i,j)
p←T[i]
# p : pivot du segment = 1er élément de la liste à grouper
m←i
# m : indice de séparation entre G1 (valeurs ≤ p) et G2 (valeurs>p)
Pour k variant entre i+1 et j-1 faire
# répéter tant que tous les éléments n'ont été lus
SiT[k]<=p faire
# si T[k] appartient à G1
m←m+1
Echange(T,m,k)
Fin Si
Fin Pour
Echange(T,i,m) # placer le pivot à sa place : indice m (l'élément initialement en m reste dans G1)
Retourner m
Fin Segmenter
Pour effectuer le tri à partir de cette fonction segmenter, on définit un deuxième algorithme récursif.
Données :
T : un tableau de valeurs numériques [0..n-1]
i, j : les indices de début et de fin de tri à effectuer (j exclu)
Résultat : le tableau T trié entre les indices i et j compris
Tri_rapide(T,i,j)
Si i < j alors
m = Segmenter(T,i,j)
Tri_rapide(T,i,m)
# m est l'indice de la dernière valeur (m exclu)
Tri_rapide(T,m+1,j)
# j est l'indice de la dernière valeur (j exclu)
Fin Si
Retourner T
Fin Tri_rapide
L'instruction suivante permet de trier la liste t0=[5, 8, 3, 2, 9] pour un fonction programmée en python :
>>> Tri_rapide(t0,0,len(t0))
[2, 3, 5, 8, 9]
Lycée Jules Ferry Cannes
Page 3 sur 4
TSI2
Informatique
Cours 4.2
Tri rapide (quick sort)
4 Performances des algorithmes
Complexité
Le « coût » temporel de l’algorithme de tri est principalement donné par des opérations de comparaison
sur les éléments à trier.
On raisonne dans la suite sur le nombre de données à traiter pour l’analyse de la complexité de
l’algorithme.
- Dans le pire des cas, un des deux segments est vide à chaque appel de la fonction segmenter.
Cela arrive lorsque le tableau est déjà trié.
Le nombre de données à traiter pour le ie appel, est n – i.
Le nombre total pour n appels de fonction est donc
(relation de récurrence du type
C(n) = C(n-1) + n – 1).
La complexité est donc de classe quadratique C(n) = O(n²).
- Dans le meilleur des cas, les deux segments sont de taille égale. Pour un nombre de données
traiter n, chacun des segments suivant a donc au plus
éléments (on retire le pivot). Il faut n-1
itérations pour réaliser la partition nécessaire au rang suivant n.
On peut ainsi écrire une relation de récurrence du type
= – 1 + 2 ∗ .
La complexité est donc de classe quasi linéaire C(n)=O(n.log(n)) (voir annexes du cours 2).
Bilan des complexités temporelle du tri rapide
meilleur des cas pire cas
comparaisons n.log(n)
n²
affectations
n.log(n)
n²
L'algorithme de tri rapide a donc des performances comparables au tri par insertion du point de vue des
complexités.
En pratique
Liste non triée
L'algorithme de tri rapide est plus rapide lorsque la probabilité de se trouver dans le pire des cas est
aléatoire (liste pas du tout triée).
Liste triée
Par contre l'algorithme de tri par insertion reste plus rapide pour des listes quasi-triées.
L'algorithme de tri rapide est à peine fonctionnel sur spyder pour une liste quasi-triée (avec
position du pivot en début de tableau) car les limites des appels récursifs sont rapidement atteintes
(n≈1000).
Une solution pour gagner en rapidité (et en nombres d'appels récursifs) avec le tri rapide est
paradoxalement de choisir des pivots à des positions aléatoires dans chaque partition. Il faut ensuite
échanger le pivot obtenu avec le premier élément du tableau afin de retomber sur les algorithmes
précédents (pivot à gauche).
Ressources :
Damien Broizat
Patrick Beynet –UPSTILycée Jules Ferry Cannes
Page 4 sur 4
TSI2
Téléchargement