QuickSort et Hoare Partition
J'ai du mal à traduire QuickSort avec Hoare de partitionnement dans le code en C, et ne peut pas savoir pourquoi. Le code que j'utilise est indiqué ci-dessous:
void QuickSort(int a[],int start,int end) {
int q=HoarePartition(a,start,end);
if (end<=start) return;
QuickSort(a,q+1,end);
QuickSort(a,start,q);
}
int HoarePartition (int a[],int p, int r) {
int x=a[p],i=p-1,j=r;
while (1) {
do j--; while (a[j] > x);
do i++; while (a[i] < x);
if (i < j)
swap(&a[i],&a[j]);
else
return j;
}
}
Aussi, je ne comprends pas trop pourquoi HoarePartition
œuvres. Quelqu'un peut-il expliquer pourquoi cela fonctionne, ou au moins de me lier à un article qui n'?
J'ai vu une étape-par-étape de travail par le biais de l'algorithme de partitionnement, mais je n'ai pas de sensation intuitive. Dans mon code, il n'a même pas l'air de fonctionner. Par exemple, compte tenu de l'éventail
13 19 9 5 12 8 7 4 11 2 6 21
Il va utiliser le pivot de 13 ans, mais jusqu'à la fin avec le tableau
6 2 9 5 12 8 7 4 11 19 13 21
Et sera de retour j
qui est a[j] = 11
. Je pensais que c'était censé être vrai que la matrice à partir de ce point et devraient avoir des valeurs qui sont plus grands que le pivot, mais ce n'est pas le cas ici car 11 < 13.
Ici de pseudo-code de Hoare de partitionnement (à partir de PLC, deuxième édition), dans le cas où c'est utile:
Hoare-Partition (A, p, r)
x ← A[p]
i ← p − 1
j ← r + 1
while TRUE
repeat j ← j − 1
until A[j] ≤ x
repeat i ← i + 1
until A[i] ≥ x
if i < j
exchange A[i] ↔ A[j]
else return j
Merci!
EDIT:
Le droit de code C pour ce problème sera à la fin:
void QuickSort(int a[],int start,int end) {
int q;
if (end-start<2) return;
q=HoarePartition(a,start,end);
QuickSort(a,start,q);
QuickSort(a,q,end);
}
int HoarePartition (int a[],int p, int r) {
int x=a[p],i=p-1,j=r;
while (1) {
do j--; while (a[j] > x);
do i++; while (a[i] < x);
if (i < j)
swap(&a[i],&a[j]);
else
return j+1;
}
}
source d'informationauteur Ofek Ron
Vous devez vous connecter pour publier un commentaire.
Je crois qu'il y a deux problèmes avec ce code. Pour commencer, dans votre fonction Quicksort, je pense que vous voulez réorganiser les lignes
de sorte que vous avez comme ceci:
Toutefois, vous devriez le faire, même plus que cela; en particulier, cela devrait lire
La raison pour cela est que la Hoare partition ne fonctionne pas correctement si la plage que vous essayez de partition a une taille de zéro ou un. Dans mon édition de CLRS ce n'est pas mentionné nulle part; j'ai dû aller à le livre de la page d'errata de trouver cela. Ce n'est presque certainement la cause du problème que vous avez rencontré avec l'accès "hors de portée" erreur, car avec cet invariant cassé vous pourriez courir à droite au large de la matrice de!
Que pour une analyse de Hoare partitionnement, je suggère de commencer par se contenter de les suivre à travers à la main. Il y a également une analyse plus détaillée ici. Intuitivement, il fonctionne par la croissance de deux plages de l'extrémité de la plage de l'une vers l'autre - l'un sur la gauche, contenant les éléments plus petits que le pivot et l'autre sur le côté droit contenant des éléments plus grands que le pivot. Il peut être légèrement modifié pour produire la Bentley-McIlroy algorithme de partitionnement (référencé dans le lien) qui s'adapte bien à la poignée de l'égalité des touches.
Espérons que cette aide!
Pour répondre à la question "Pourquoi ne Hoare partitionnement de travail?":
Simplifions les valeurs dans le tableau de trois sortes: L valeurs (celles de moins que le pivot de la valeur), E valeurs (celles égale à la valeur pivot), et G valeur (ceux plus grands que le pivot de la valeur).
Nous allons aussi donner un nom spécial à un seul endroit dans le tableau; nous l'appellerons cet emplacement set c'est l'endroit où l' j pointeur est lorsque la procédure se termine. - Nous savoir à l'avance à quel endroit s est? Non, mais nous savons que certains emplacement de répondre à cette description.
Avec ces conditions, nous pouvons exprimer l'objectif de la procédure de partitionnement dans des termes légèrement différents: il consiste à diviser un groupe en deux sous-ensembles qui sont pas mal triés à l'égard les uns des autres. Que "pas mal triés" exigence est satisfaite si les conditions suivantes sont remplies:
C'est vraiment tout ce que nous devons faire. Nous n'avons même pas besoin de s'inquiéter lorsque le E valeurs de liquidation sur tout passer. Tant que chaque laissez-passer de la sous-matrices de droit à l'égard les uns des autres, plus tard, passe va prendre soin de tout le désordre qui existe à l'intérieur d'un sous-tableau.
Alors maintenant, nous allons traiter de la question de l'autre côté: comment fonctionne la procédure de partitionnement s'assurer qu'il n'y a pas G valeurs dans s ou à gauche de celle-ci, et pas de L les valeurs à droite de s?
Bien, "l'ensemble des valeurs à droite de s" est le même que "l'ensemble des cellules de la j pointeur se déplace avant qu'il n'atteigne s". Et "l'ensemble des valeurs de la gauche et notamment s" est le même que "l'ensemble des valeurs que la je pointeur se déplace avant j atteint s".
Qui signifie que toutes les valeurs qui sont mal placée, sur une itération de la boucle, dans l'une de nos deux pointeurs. (Pour plus de commodité, disons que c'est le j pointeur pointant sur un L valeur, si elle fonctionne exactement de même pour le je pointeur pointant sur un G valeur.) D'où l' je pointeur, lorsque le j pointeur est sur un égaré de la valeur? Nous savons qu'il sera:
Noter que, parfois, la je et j pointeur de la réalité à la fois s'arrêter sur E valeurs. Lorsque cela se produit, les valeurs seront allumés, même si il n'est pas nécessaire pour cela. Ce n'est pas plus mal, bien que nous l'avons dit avant que le placement de la E valeurs ne peuvent pas causer de mal le tri entre les sous-tableaux.
Donc, pour résumer, Hoare partitionnement fonctionne parce que:
Votre code final est mauvais, depuis la valeur initiale de
j
devrait êtrer + 1
au lieu der
. Sinon, votre fonction de partition ignorer toujours la dernière valeur.En fait, HoarePartition fonctionne parce que pour n'importe quel tableau
A[p...r]
qui contient au moins 2 éléments(c'est à direp < r
), chaque élément deA[p...j]
est<=
chaque élément deA[j+1...r]
lorsqu'il se termine.Si les deux segments que l'algorithme revient sur sont
[start...q]
et[q+1...end]
De sorte que le droit du code C est comme suit:
Plus de précisions:
partition partie est tout simplement la traduction du pseudo-code. (Note de la valeur de retour est
j
)pour la partie récursive, notez que le cas de base de la vérification (
end <= start
au lieu deend <= start + 1
sinon vous passez la[2 1]
subarray )Vous dernier C un code qui fonctionne. Mais ce n'est pas intuitive.
Et maintenant, je suis étudiant en CLRS heureusement.
À mon avis, Le pseudo-code de PLC est mauvais.(2e)
Enfin, je trouve que ce serait bon si la modification d'un lieu.
Oui, Ajoutez un échange d'Un[r] ↔ A[i] peut faire cela fonctionne.
Pourquoi?
Parce que A[i] est maintenant plus grand que Un[r] OU i == r.
Nous Nous devons donc d'échange afin de garantir la fonctionnalité d'une partition.
0 -- cmp(val, pivot) == true, 1 -- cmp(val, pivot) == false.
arrêt si pas de gauche < droite.
Tout d'abord u mal compris la Hoare partition de l'algorithme,qui peut être voir à partir de la traduction du code en c,
Depuis u considéré comme pivot le plus à gauche de l'élément de subarray.
Mal expliquer u compte tenu de la plus à gauche de l'élément de pivot.
Ici p et r représente la partie inférieure et la limite supérieure de la matrice qui peut être partie d'un ensemble plus grand aussi(subarray) être partitionné.
nous commençons donc avec les pointeurs(marqueur) au départ de pointage avant et après les points de fin de tableau(simplement bcoz à l'aide de boucle do while).Par conséquent,
Maintenant que par le partitionnement nous voulons que chaque élément à gauche du pivot être inférieure ou égale à pivot et plus grand que sur le côté droit de pivot.
Donc, nous allons aller de l' " je " marqueur jusqu'à ce que nous obtenir l'élément qui est greaterthan ou égale à pivot. Et, de même, 'j' marqueur jusqu'à ce que nous trouver l'élément inférieur ou égal à pivot.
Maintenant, si i < j on échange les éléments bcoz à la fois les éléments sont dans la mauvaise partie du tableau. Donc le code sera
Maintenant, si " je " n'est pas inférieur à 'j',ce qui veut dire que il n'y a aucun élément dans entre de swap si nous revenons 'j' position.
Donc maintenant le tableau après avoir partitionné moitié inférieure est de "commencer à j'
moitié supérieure est à partir de j+1 à la fin"
donc le code ressemblera à
Simple mise en œuvre en java.