Quicksort: Choisir le pivot

voix
94

Lors de la mise en œuvre Quicksort, l'une des choses que vous avez à faire est de choisir un pivot. Mais quand je regarde comme pseudocode celui ci-dessous, on ne sait pas comment je dois choisir le pivot. Premier élément de la liste? Autre chose?

 function quicksort(array)
     var list less, greater
     if length(array) ≤ 1  
         return array  
     select and remove a pivot value pivot from array
     for each x in array
         if x ≤ pivot then append x to less
         else append x to greater
     return concatenate(quicksort(less), pivot, quicksort(greater))

Quelqu'un peut-il me aider à comprendre le concept de choisir un pivot et si oui ou non les différents scénarios exigent des stratégies différentes.

Créé 02/10/2008 à 20:37
source utilisateur
Dans d'autres langues...                            


13 réponses

voix
72

Le choix d' un pivot aléatoire réduit la chance que vous rencontrerez le pire des cas O (n 2 ) les performances ( en choisissant toujours premier ou le dernier causerait la performance pire des cas pour les données presque triées ou presque inverse triées). Le choix l'élément central serait également acceptable dans la majorité des cas.

En outre, si vous implémentez vous-même, il existe des versions de l'algorithme qui fonctionnent en place (sans créer deux nouvelles listes et les concaténer).

Créé 02/10/2008 à 20:41
source utilisateur

voix
47

Cela dépend de vos besoins. Le choix d'un pivot de manière aléatoire, il est plus difficile de créer un ensemble de données qui génère O (N ^ 2) la performance. « Médian de trois enfants » (premier, dernier, milieu) est aussi un moyen d'éviter les problèmes. Méfiez-vous des performances relatives des comparaisons, cependant; si vos comparaisons sont coûteuses, alors Mo3 ne comparaisons plus que le choix (une seule valeur de pivot) au hasard. les dossiers de base de données peuvent être coûteuses à comparer.


Mise à jour: Tirer les commentaires en réponse.

mdkess a affirmé:

« Médian de 3 » est pas le premier dernier milieu. Choisissez trois indices aléatoires, et prendre la valeur moyenne de cela. Le tout est de vous assurer que votre choix de pivots n'est pas déterministe - si elle est, les pires données de cas peuvent être facilement générés.

Ce à quoi je répondais:

  • Analyse de l'algorithme de Recherche de Hoare Avec cloison médiane de trois enfants (1997) par P Kirschenhofer, H Prodinger, C Martínez soutient votre affirmation (que « médiane de trois enfants » est trois éléments aléatoires).

  • Il y a un article décrit à portal.acm.org qui est sur « le pire des cas pour Permutation médian de trois enfants Quicksort » par Hannu Erkiö, publié dans The Computer Journal, vol 27, n ° 3, 1984. [Mise à jour 2012-02- 26: Vous avez le texte de l' article . Section 2 « L'algorithme » commence: « En utilisant la médiane des premiers éléments du milieu et la dernière de A [L: R], partitions efficaces en parties égales de tailles assez peut être réalisée dans des situations les plus pratiques. »Ainsi, il discute de la première mi-dernière approche Mo3.]

  • Un autre article court qui est intéressant est de MD McIlroy, « Un tueur pour Adversaire Quicksort » , publié dans le logiciel-pratique et de l' expérience, vol. 29 (0), 1-4 (0 , 1999). Il explique comment faire presque tous les Quicksort se comportent quadratiquement.

  • AT & T Bell Labs Tech Journal, octobre 1984 « Théorie et pratique dans la construction d'un travail Trier routine » états « Hoare a suggéré le partitionnement autour de la médiane de plusieurs lignes choisies au hasard. Sedgewick [...] recommandé de choisir la médiane du premier [. ..] dernier [...] et au milieu ». Cela indique que les deux techniques pour « médian des trois » sont connus dans la littérature. (Mise à jour 23/11/2014: L'article semble être disponible à IEEE Xplore ou de Wiley - si vous avez l' adhésion ou êtes prêt à payer les frais.)

  • « Ingénierie une fonction de tri » par JL Bentley et MD McIlroy, publié dans la pratique du logiciel et de l' expérience, vol 23 (11), Novembre 1993, va dans une discussion approfondie sur les questions, et ils ont choisi un algorithme de partitionnement adaptatif basé en partie sur la taille de l'ensemble de données. Il y a beaucoup de discussions de compromis pour différentes approches.

  • Une recherche sur Google pour « médian de trois » fonctionne assez bien pour le suivi plus loin.

Merci pour l'information; Je n'avais rencontré la « médiane de trois » déterministe avant.

Créé 02/10/2008 à 20:42
source utilisateur

voix
1

Si vous triez une collection aléatoire accessible (comme un tableau), il est en général préférable de choisir l'élément du milieu physique. Avec cela, si le tableau est tout prêt trié (ou presque triée), les deux partitions seront proches de même, et vous obtiendrez la meilleure vitesse.

Si vous triez quelque chose avec seulement un accès linéaire (comme une liste chaînée), alors il est préférable de choisir le premier élément, parce qu'il est le plus rapide point d'accès. Ici, cependant, si la liste est déjà triée, vous êtes foutus - une partition sera toujours nulle, et l'autre ont tout, produisant le pire moment.

Cependant, pour une liste chaînée, picking autre chose que le premier, va juste faire empirer les choses. Il choisir l'élément du milieu dans une liste la liste, vous auriez à parcourir sur chaque étape de la partition - l'ajout d'une opération O (N / 2) qui est fait temps logN rendant le temps total O (1,5 N * log N) et c'est si nous savons combien de temps la liste est avant de commencer - en général, nous ne nous serions pas à l'étape a tout au long de les compter, alors l'étape à mi-chemin jusqu'à trouver le milieu, puis l'étape à travers un troisième fois pour faire la partition réelle: O (log N * 2,5 N)

Créé 02/10/2008 à 20:42
source utilisateur

voix
1

Il est entièrement dépendant de la façon dont vos données sont triées pour commencer. Si vous pensez que ce sera pseudo-aléatoire alors votre meilleur pari est de choisir soit une sélection aléatoire ou choisir le milieu.

Créé 02/10/2008 à 20:46
source utilisateur

voix
16

Heh, je viens enseigné cette classe.

Il y a plusieurs options.
Simple: Choisissez le premier ou le dernier élément de la gamme. (mauvaise sur l' entrée partiellement triée) Mieux: Choisissez l'élément au milieu de la gamme. (mieux sur l' entrée partiellement triée)

Cependant, choisir un élément arbitraire court le risque de cloisonnement mal le tableau de taille n en deux tableaux de taille 1 et n-1. Si vous faites cela assez souvent, votre quicksort court le risque de devenir O (n ^ 2).

Une amélioration que j'ai vu est de choisir la médiane (premier, dernier, milieu); Dans le pire des cas, il peut toujours aller à O (n ^ 2), mais probabilistes, c'est un cas rare.

Pour la plupart des données, choisir la première ou la dernière est suffisante. Mais, si vous trouvez que vous utilisez dans le pire des scénarios souvent (entrée partiellement triés), la première option serait de choisir la valeur centrale (ce qui est un bon pivot statistiquement pour les données partiellement triées).

Si vous êtes toujours en cours d'exécution dans des problèmes, puis emprunter la voie médiane.

Créé 02/10/2008 à 20:46
source utilisateur

voix
8

Ne jamais choisir un pivot fixe - ce qui peut être attaqué pour exploiter votre temps d'exécution pire des cas O de l'algorithme (n ^ 2), qui vient d'avoir des ennuis. pire temps d'exécution des cas de Quicksort se produit lorsque le partitionnement des résultats dans une gamme de 1 élément, et une rangée de n-1 éléments. Supposons que vous choisissez le premier élément que votre partition. Si quelqu'un alimente un tableau à votre algorithme qui est dans l'ordre décroissant, votre premier pivot sera le plus grand, donc tout le reste dans le tableau se déplace vers la gauche. Puis, quand vous RECURSE, le premier élément sera le plus grand encore, donc une fois de plus vous mettez tout à gauche de celui-ci, et ainsi de suite.

Une meilleure technique est la méthode médiane de-3, où vous choisissez trois éléments au hasard, et choisir le milieu. Vous savez que l'élément que vous choisissez ne sera pas le premier ou le dernier, mais aussi, par le théorème central limite, la répartition de l'élément central sera normal, ce qui signifie que vous aurez tendance vers le milieu (et par conséquent , n lg n fois).

Si vous voulez absolument garantir O (NLGN) l'exécution de l'algorithme, la méthode colonnes de-5 pour trouver la médiane d'un tableau passe en O (n), ce qui signifie que l'équation de récurrence pour quicksort dans le pire des cas sera être T (n) = O (n) (trouver la médiane) + O (n) (partition) + 2T (n / 2) (rECURSE gauche et à droite.) Par le théorème de Maître, c'est O (nlogn) . Cependant, le facteur constant sera énorme, et si pire performance de cas est votre principale préoccupation, utilisez un tri par fusion au lieu, qui est seulement un peu plus lent que quicksort en moyenne, et garantit O (NLGN) temps (et sera beaucoup plus rapide que ce quicksort médian boiteux).

Explication de la médiane de l'algorithme Médianes

Créé 25/10/2008 à 22:50
source utilisateur

voix
5

Ne pas essayer d'obtenir trop intelligent et combiner les stratégies de pivotement. Si vous médian combiné de 3 avec le pivot aléatoire en choisissant la médiane du premier, dernier et un indice aléatoire au milieu, alors vous serez toujours vulnérable à la plupart des distributions qui envoient médiane de 3 quadratique (donc sa pire que simple pivot aléatoire)

Par exemple, une distribution d'organe de tuyau (1,2,3 ... N / 2..3,2,1) premier et dernier seront tous deux 1 et l'indice aléatoire sera un nombre supérieur à 1, en prenant la médiane donne une ( soit premier ou dernier) et vous obtenez une répartition déséquilibrée extermely.

Créé 26/10/2008 à 04:54
source utilisateur

voix
1

Il est plus facile de briser le quicksort en trois sections faisant

  1. Échange ou d'échange fonction élément de données
  2. La fonction de partition
  3. Traitement des partitions

Il est seulement un peu plus d'une fonction inefficent long, mais est beaucoup plus facile à comprendre.

Code suit:

/* This selects what the data type in the array to be sorted is */

#define DATATYPE long

/* This is the swap function .. your job is to swap data in x & y .. how depends on
data type .. the example works for normal numerical data types .. like long I chose
above */

void swap (DATATYPE *x, DATATYPE *y){  
  DATATYPE Temp;

  Temp = *x;        // Hold current x value
  *x = *y;          // Transfer y to x
  *y = Temp;        // Set y to the held old x value
};


/* This is the partition code */

int partition (DATATYPE list[], int l, int h){

  int i;
  int p;          // pivot element index
  int firsthigh;  // divider position for pivot element

  // Random pivot example shown for median   p = (l+h)/2 would be used
  p = l + (short)(rand() % (int)(h - l + 1)); // Random partition point

  swap(&list[p], &list[h]);                   // Swap the values
  firsthigh = l;                                  // Hold first high value
  for (i = l; i < h; i++)
    if(list[i] < list[h]) {                 // Value at i is less than h
      swap(&list[i], &list[firsthigh]);   // So swap the value
      firsthigh++;                        // Incement first high
    }
  swap(&list[h], &list[firsthigh]);           // Swap h and first high values
  return(firsthigh);                          // Return first high
};



/* Finally the body sort */

void quicksort(DATATYPE list[], int l, int h){

  int p;                                      // index of partition 
  if ((h - l) > 0) {
    p = partition(list, l, h);              // Partition list 
    quicksort(list, l, p - 1);        // Sort lower partion
    quicksort(list, p + 1, h);              // Sort upper partition
  };
};
Créé 10/03/2011 à 03:19
source utilisateur

voix
0

Idéalement, le pivot devrait être la valeur moyenne dans l'ensemble du réseau. Cela permettra de réduire les chances d'obtenir pire performance de cas.

Créé 17/04/2013 à 15:57
source utilisateur

voix
-1

Dans une mise en œuvre optimisée vraiment, la méthode de choix de pivot devrait dépendre de la taille du tableau - pour un grand tableau, il est rentable de passer plus de temps à choisir un bon pivot. Sans faire une analyse complète, je suppose que « milieu de O (log (n)) des éléments » est un bon point de départ, ce qui a l'avantage de ne pas nécessiter de mémoire supplémentaire: Utilisation appel de la queue sur la partition plus grande et in- lieu le partitionnement, nous utilisons le même O (log (n)) de mémoire supplémentaire à presque toutes les étapes de l'algorithme.

Créé 08/10/2013 à 20:50
source utilisateur

voix
0

La complexité de tri rapide varie grandement avec la sélection de la valeur de pivot. par exemple, si vous choisissez toujours premier élément comme un pivot, la complexité de l'algorithme devient aussi pire que O (n ^ 2). voici une méthode intelligente pour choisir pivot element- 1. choisir le premier, mi, dernier élément du tableau. 2. comparer ces trois chiffres et trouver le nombre qui est supérieur à un et plus petit que les autres à savoir médiane. 3. faire de cet élément comme élément de pivot.

le choix du pivot par cette méthode divise la matrice en deux à peu près la moitié et donc la complexité réduit à O (nlog (n)).

Créé 05/12/2013 à 06:05
source utilisateur

voix
0

En moyenne, médiane de 3 est bon pour les petits n. Médian 5 est un peu mieux pour plus n. Le ninther, qui est la « médiane de trois médianes de trois » est encore mieux pour n très grand.

Plus vous allez avec échantillonnage plus vous obtenez comme n augmente, mais l'amélioration ralentit considérablement vers le bas que vous augmentez les échantillons. Et vous encourez les frais généraux d'échantillonnage et d'échantillons de tri.

Créé 19/10/2016 à 10:04
source utilisateur

voix
0

Je recommande d'utiliser l'indice du milieu, car il peut être calculé facilement.

Vous pouvez le calculer en arrondissant (array.length / 2).

Créé 09/08/2017 à 01:29
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more