Je trouve cette approche de partitionnement Quicksort confuse et erronée, mais elle semble fonctionner. Je fais référence à this pseudocode. Note: ils ont aussi une implémentation C à la fin de l'article, mais c'est très différent de leur pseudo-code, donc ça m'est égal.Pourquoi ce Quicksort fonctionne-t-il?
J'ai aussi écrit en C comme celui-ci, en essayant de rester fidèle à la pseudocode autant que possible, même si cela signifie faire des choses C bizarre:
#include <stdio.h>
int partition(int a[], int p, int r)
{
int x = a[p];
int i = p - 1;
int j = r + 1;
while (1)
{
do
j = j - 1;
while (!(a[j] <= x));
do
i = i + 1;
while (!(a[i] >= x));
if (i < j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
else
{
for (i = 1; i <= a[0]; ++i)
printf("%d ", a[i]);
printf("- %d\n", j);
return j;
}
}
}
int main()
{
int a[100] = //{8, 6,10,13,15,8,3,2,12};
{7, 7, 6, 2, 3, 8, 4, 1};
partition(a, 1, a[0]);
return 0;
}
Si vous exécutez, vous » ll obtenir la sortie suivante:
1 6 2 3 4 8 7 - 5
Cependant, cela est faux, non? Clairement, a[5]
n'a pas toutes les valeurs avant qu'il ne soit plus bas que lui, puisque a[2] = 6 > a[5] = 4
. Sans compter que 7
est censé être le pivot (le a[p]
initial) et pourtant sa position est à la fois incorrecte et perdue.
L'algorithme de partition suivant est extrait de wikipedia:
int partition2(int a[], int p, int r)
{
int x = a[r];
int store = p;
for (int i = p; i < r; ++i)
{
if (a[i] <= x)
{
int t = a[i];
a[i] = a[store];
a[store] = t;
++store;
}
}
int t = a[r];
a[r] = a[store];
a[store] = t;
for (int i = 1; i <= a[0]; ++i)
printf("%d ", a[i]);
printf("- %d\n", store);
return store;
}
et produit cette sortie:
1 6 2 3 8 4 7 - 1
qui est un bon résultat dans mon avis: le pivot (a[r] = a[7]
) a atteint sa position finale.
Cependant, si j'utilise la fonction de partitionnement initial dans l'algorithme suivant:
void Quicksort(int a[], int p, int r)
{
if (p < r)
{
int q = partition(a, p, r); // initial partitioning function
Quicksort(a, p, q);
Quicksort(a, q + 1, r); // I'm pretty sure q + r was a typo, it doesn't work with q + r.
}
}
... il semble être un algorithme de tri correct. J'ai testé sur beaucoup d'entrées aléatoires, y compris tous les tableaux 0-1 de longueur 20.
J'ai également essayé d'utiliser cette fonction de partition pour un algorithme de sélection, dans lequel il n'a pas réussi à produire des résultats corrects. Cela semble fonctionner et c'est même très rapide dans le cadre de l'algorithme quicksort.
Mes questions sont les suivantes:
- Quelqu'un peut-il afficher un exemple sur lequel l'algorithme ne fonctionne pas?
- Si non, pourquoi cela fonctionne-t-il, puisque la partition semble être incorrecte? Est-ce une autre approche de partitionnement que je ne connais pas?
Vous voulez dire que c'est correct parce que 'a [1..5]' a des éléments <= '7' et' a [6..7] 'a des éléments> =' 7'? C'est vrai, mais le pivot sélectionné ne devrait-il pas atteindre sa position finale? Selon mes manuels et wikipedia, il devrait. – IVlad
Oui. Dans le premier lien que vous avez donné, quicksort procède alors au tri d'un [1..5] et d'un [6..7]. Seulement dans le lien wikipedia a [6] est nécessaire pour avoir sa valeur finale de 7, comme ici un [1..5] et un [7..7] sont triés dans les appels récursifs. – Henrik
Intéressant, je n'y ai pas pensé comme ça. J'ai toujours pensé que l'algorithme de partitionnement est supposé renvoyer la position finale de l'élément pivot. Merci pour votre explication. J'accepterai votre réponse un peu plus tard pour donner aux autres l'occasion de commenter cet algorithme aussi. – IVlad