L’un des algorithmes de tri les plus répandus est QuickSort. C’est un algorithme « diviser pour régner » qui choisit itérativement un pivot dans le tableau, scinde le tableau en 3 parties – les éléments plus petits, égaux et plus grands que le pivot – et répète ce processus jusqu’à ce que le tableau soit entièrement trié.
Donc, à chaque itération :
On choisit un élément pivot dans le tableau
On déplace les éléments plus petits à gauche du pivot
On déplace les éléments plus grands à droite du pivot
On regroupe tous les éléments égaux au pivot au milieu
On répète ce processus sur les parties gauche et droite
def quicksort(a):
if len(a) <= 1:
return a
pivot = a[len(a) // 2]
left = [x for x in a if x < pivot]
middle = [x for x in a if x == pivot]
right = [x for x in a if x > pivot]
return quicksort(left) + middle + quicksort(right)
Cette implémentation de QuickSort utilise des tableaux supplémentaires pour les parties left, middle et right. Nous pouvons le rendre “in place” (en place) en modifiant le code pour utiliser des indices et réorganiser les éléments directement dans le tableau.
def quicksort(a, start, end):
if start >= end: # Aucun élément à trier
return
pivot = a[start] # Choisir un pivot
l, r = start + 1, end # Trier a[start+1 ... end]
while l <= r: # Tant qu'il reste des éléments dans la plage
if a[l] < pivot: # si a[l] < pivot => on ne touche pas a[i]
l += 1 # Incrémenter le pointeur gauche
else: # sinon déplacez a[l] vers la fin
a[l], a[r] = a[r], a[l] # Échanger a[l] et a[r] -> déplacer vers la fin
r -= 1 # Décrémenter le pointeur droit
a[start], a[r] = a[r], a[start] # Échanger le pivot avec a[r]
quicksort(a, start, r - 1) # Trier a[start ... r-1]
quicksort(a, r + 1, end) # Trier a[r+1 ... end]
Vous avez peut-être remarqué que le choix du pivot différait dans ces deux implémentations. L’algorithme QuickSort n’impose pas de règle stricte pour le choix du pivot. Il existe plusieurs façons de le choisir. En voici quelques-unes :
Premier élément : a[start], comme dans la deuxième implémentation
Dernier élément : a[end]
Élément du milieu : a[(start + end + 1) // 2]
Élément aléatoire : choisir n’importe quel élément dans a[start ... end]
Élément médian : choisir la médiane du segment courant. Cela garantit une répartition égale entre left et right, mais requiert une implémentation plus sophistiquée.
Faisons une simulation de l’algorithme sur plusieurs tableaux :
Le temps d’exécution moyen de l’algorithme QuickSort est . Cependant, selon la façon dont on choisit le pivot, le temps d’exécution peut devenir quadratique .
🤔 Pouvez-vous imaginer un exemple où l’algorithme effectuerait opérations si l’on choisit toujours start comme pivot ?
Challenge
Étant donné une liste de n entiers et q pivots, le but est de déplacer tous les éléments plus petits que le pivot à gauche, et tous les éléments plus grands à droite de cet élément pivot, tout en conservant ensemble tous ceux qui lui sont égaux (regroupés à la suite des nombres plus petits et à l’intérieur des nombres plus grands).
Entrée
La première ligne de l’entrée contient un seul entier n (1 ≤ n ≤ 100 000).
La ligne suivante contient une liste de n entiers séparés par des espaces ( ≤ ≤ ).
La troisième ligne contient un seul entier q (1 ≤ q ≤ 10).
La ligne suivante contient une liste de n entiers séparés par des espaces (1 ≤ ≤ n) qui représentent l’indice de l’élément pivot.
Sortie
Pour chacun des q pivots, le programme doit afficher le tableau résultant après avoir effectué le réarrangement. S’il existe plusieurs réponses possibles, le programme peut en imprimer n’importe laquelle.