«Quicksort ou Quick-Sort est un algorithme de tri. Le tri rapide est un algorithme de division et de conquête. Que la liste des personnages soit triée par:
Q w e r t y u i o p
La liste triée est:
E i o p q r t u w y
C'est en quelque sorte ascendant. Dans cet article, l'explication de Quicksort, trie ascendante, en utilisant la liste: "Q", "W", "E", "R", "T", "Y", "U", "I", " O ”,« P », et la langue C."
Sort rapide en théorie
De la liste, «Q», «W», «E», «R», «T», «Y», «U», «I», «O», «P», pour une valeur centrale, appelée le pivot. Dans la liste triée,
"E", "i", "o", "p", "Q", "r", "t", "u", "w", "y"
Le pivot est soit «Q» ou «R» car la liste est même en nombre. Si la liste était en nombre impair, le pivot aurait clairement été la valeur moyenne. «Q» à l'index 4 est choisi comme pivot. N'oubliez pas que la liste à tri est,
Q w e r t y u i o p
Et pas la liste triée. Il y a 10 éléments dans cette liste non triée.
La première étape consiste à rechercher le pivot (valeur centrale) dans la liste non triée. La deuxième étape consiste à placer le pivot dans sa position légitime dans la liste non triée (dans ce cas, index 4); et mettez tous les éléments qui sont inférieurs au pivot à gauche et tous les éléments qui sont supérieurs au pivot à droite. Les éléments à gauche du pivot ne doivent pas nécessairement être triés, et les éléments à droite du pivot ne doivent pas nécessairement être triés. Cette phase est la phase de division ou de partition dans l'algorithme de division et de conquête. Il y a trois parties pour cette étape: la sous-liste gauche, la sous-liste droite et la sous-liste moyenne. La sous-liste moyenne se compose d'un seul élément, qui est le pivot. Pour la liste ci-dessus, le résultat serait:
E i o p q w r t y u
Puisque le pivot est déjà à sa position finale, la dernière étape, en théorie, est de trier la sous-liste gauche et de trier la sous-liste droite. C'est conquérant. C'est une coïncidence que la sous-liste gauche, dans ce cas, soit déjà triée. La bonne liste, dans ce cas, doit encore être triée. Tri de la sous-liste gauche et droite séparément, le résultat est:
E i o p q r t u w y
comme demandé.
Sort rapide dans la pratique
En pratique, le partitionnement avec un certain tri (échange) se fait à plusieurs reprises de manière récursive. C'est-à-dire que de nouvelles sous-listes de plus en plus petites sont développées avec leurs propres pivots. En d'autres termes, des sous-listes de plus en plus petites en trois parties sont développées à partir de la liste principale jusqu'à ce que toute la liste soit triée.
Il y a un problème quand il s'agit de choisir le pivot. L'ensemble de la liste non triée ne peut pas être scanné un élément par élément pour obtenir le bon pivot. Ce sera long. Donc une supposition intelligente doit être faite.
N'oubliez pas que la liste à tri est:
Q w e r t y u i o p
Que la supposition intelligente soit p, l'élément le plus à droite. Ensuite, laissez tous les éléments inférieurs à P, lisant de la gauche, allez à gauche de P, et laissez tous les éléments supérieurs à P, en lisant toujours de la gauche, allez à droite de P sans tri conscient. Cela donne:
E i o p q w r t y u
Les trois premiers sous-listes sont:
"E", "i", "o", "p", "Q", "w", "r", "t", "y", "u"
P est à sa position légitime (en pratique, ce n'est pas nécessairement l'index 4; ici, c'est l'index 3 à ce stade). L'étape suivante est un appel récursif pour diviser la sous-liste gauche en trois sous-listes; Et le sous-liste de droite en trois sous-listes, chacun avec son propre pivot, d'une supposition intelligente.
Diviser "e", "i", "o"
Laissez son pivot intelligent deviner être, o, l'élément le plus à droite. Tous les éléments qui sont inférieurs à O doivent aller à gauche, et tous les éléments supérieurs à O doivent aller à droite, lire pour les deux cas depuis la gauche. Cela donne:
"E", "i", "o",
sans élément à droite. Si "e", "i" est également divisé récursivement, alors ["e", "i", ]. Et donc la première sous-liste gauche triée, est:
"E", "I", "O"
Divisant "q", "w", "r", "t", "y", "u"
"Q", "w", "r", "t", "y", "u" est le premier sous-liste. Laissez son pivot intelligent deviner être u, l'élément le plus à droite. Tous les éléments qui sont moins que vous devez aller à gauche, et tous les éléments qui sont plus grands que vous devez aller à droite; lecture pour les deux cas, de la gauche. Cela donne:
"Q", "r", "t", "u", "w", "t"
En partageant récursivement "Q", "R", "T" et "W", "T" De la même manière, le premier sous-liste de droite serait:
"Q", "r", "t", "u", "w", "y"
Et la liste triée complète serait:
E i o p q r t u w y
Notez que chaque partition fait le tri dans un sens large en plaçant des valeurs inférieures non triées sur la gauche et des valeurs plus élevées non triées à droite.
Notez également que la supposition intelligente était de choisir le bon élément le plus élevé d'une sous-liste. Ce n'est pas la meilleure supposition intelligente. D'un autre côté, la solution (pour une supposition intelligente) n'est pas de scanner toute la liste donnée! - Voir ci-dessous pour de meilleures options.
Code de tri rapide en C
Bien que la valeur la plus droite ait été choisie pour chaque sous-liste ci-dessus, conventionnellement, c'est la valeur la plus à gauche qui est choisie. Même lorsqu'une supposition plus intelligente est faite, la bonne valeur devinée devra être placée dans la position la plus à gauche; et la valeur de gauche qui était là sera placée dans une autre position appropriée (toujours dans la liste).
Il y a quatre fonctions C avec les noms, swap (), pivot (), partition () et Quicksort (). Quicksort (), la fonction, est codé de manière récursive, et il appelle les autres fonctions.
La fonction swap ()
Cette fonction échange deux éléments de tableau, en utilisant leurs indices. C'est:
vide swap (char a [], int m, int n)
char à char = a [m];
A [m] = a [n];
A [n] = temp;
Une fonction pivot simple ()
Cette fonction choisit entre l'élément le plus gauche et l'élément le plus droit de la liste entière donnée. Il met le moindre de la position la plus à gauche et le plus grand à la position la plus droite. C'est:
void pivot (char a [], int gauche, int droit)
if (a [gauche]> a [à droite])
échange (a, à gauche, à droite);
C'est mieux que le simple choix du bon élément le plus pour la liste et les sous-listes, comme fait ci-dessus. Une fonction pivot () encore meilleure est donnée ci-dessous.
Une fonction partition ()
Tout comme la fonction pivot () peut être écrite de différentes manières, la fonction partition () peut être écrite de différentes manières. Celui choisi pour cet article est:
int partition (char a [], int gauche, int droit)
int pivot = a [gauche];
int i = gauche;
int j = droit + 1;
faire
faire ++ i;
tandis que (un [i] pivot);
si je < j)
échange (a, i, j);
alors que je < j);
échange (a, j, à gauche);
retour j;
Après avoir placé l'élément pivot à la position la plus gauche de la liste ou de la sous-liste, par la fonction pivot (), la fonction de partition scanne la liste ou la liste des deux extrémités, échangeant les éléments qui ne sont pas du bon côté du pivot. La numérisation à partir de l'extrémité gauche commence après le pivot de l'extrémité la plus gauche (de la liste ou de la sous-liste); Parce que le pivot sera échangé en dernier («do ++ i;» ci-dessus).
L'indice de retour, j, est la nouvelle (prochaine) position de pivot.
La fonction Quicksort ()
Ceci est une fonction récursive qui appelle les autres fonctions. C'est:
void Quicksort (char a [], int gauche, int droit)
Si (à gauche < right)
pivot (a, à gauche, à droite);
int k = partition (a, gauche, droite);
Quicksort (A, à gauche, K-1);
Quicksort (A, K + 1, à droite);
Ici, k est le même que j est retourné ci-dessus.
Toutes les fonctions ci-dessus codées ensemble, dans l'ordre décrit, formeront le programme QuickSort.
La fonction principale C
Une fonction principale C appropriée pour tester le programme est:
int main (int argc, char ** argv)
char a [] = «q», «w», «e», «r», «t», «y», «u», «i», «o», «p»;
int sz = sizeof (a) / sizeof (a [0]);
Quicksort (A, 0, SZ-1);
pour (int i = 0; iprintf ("% c", a [i]);
printf ("\ n");
retour 0;
La fonction Quicksort () proprement dite est appelée de la fonction principale C, passant le tableau comme le premier argument. Le deuxième argument qui reste est un index, 0, de toute la liste. Le troisième argument, à droite, est le dernier mais un index de toute la liste.
Pivot médian
Si trois nombres différents sont organisés par ordre croissant, alors la médiane est la valeur moyenne (deuxième). Une meilleure façon que la précédente, d'obtenir le pivot, est de rechercher la médiane, entre la valeur la plus à gauche, la valeur moyenne de la liste ou du sous-liste, et la valeur la plus à droite. Le code est:
int midIndex = (gauche + droite) / 2; // Nombre entier pris
si (un [midindex] < A[left])
échange (a, gauche, midindex);
si (un [à droite] < A[left])
échange (a, à gauche, à droite);
si (un [midindex] < A[right])
échange (a, midindex, à droite);
char pivot = a [à droite];
Remarquez que les trois éléments peuvent avoir changé de position. Ce code est combiné avec la fonction pivot () ci-dessus à avoir:
void pivot (char a [], int gauche, int droit)
// Obtention de la médiane
int midIndex = (gauche + droite) / 2; // Nombre entier pris
si (un [midindex] < A[left])
échange (a, gauche, midindex);
si (un [à droite] < A[left])
échange (a, à gauche, à droite);
si (un [midindex] pivot)
échange (a, à gauche, à droite); // sinon, une [gauche] est le pivot
Notez la dernière condition IF.
Conclusion
Quick-Sort est un algorithme de tri Divide and Conquers. Il continue de diviser (partitionner) la liste en trois sous-listages récursivement. La sous-liste moyenne se compose toujours d'un élément, qui est le pivot. En faisant le pivot, le tri se fait dans un sens large à cette étape. Cependant, au fur et à mesure que la récursivité se poursuit, un tri parfait est obtenu à la fin du programme.