Sortarerapidă: Alegerea pivotul

voturi
94

La punerea în aplicare Quicksort, unul dintre lucrurile pe care trebuie să faceți este de a alege un pivot. Dar când mă uit la pseudocod ca cea de mai jos, nu este clar cum ar trebui să aleg pivotul. Primul element de listă? Altceva?

 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))

Poate cineva să mă ajute să înțeleagă conceptul de a alege un pivot sau nu și dacă scenarii diferite necesită strategii diferite.

Întrebat 02/10/2008 la 20:37
sursa de către utilizator
În alte limbi...                            


13 răspunsuri

voturi
72

Alegerea unui pivot aleatoriu minimizează șansele pe care le va întâlni cel mai rău caz O (n 2 ) de performanță (alegând întotdeauna primul sau ultimul ar duce la o performanță cel mai rău caz pentru datele de aproape-sortate sau aproape-reverse-sortate). Alegerea elementului de mijloc ar fi , de asemenea , acceptabil , în majoritatea cazurilor.

De asemenea, dacă punerea în aplicare a acestei le există versiuni ale algoritmului care lucrează în loc (de exemplu, fără a crea două liste noi și apoi le concatenand).

Publicat 02/10/2008 la 20:41
sursa de către utilizator

voturi
47

Aceasta depinde de cerințele dumneavoastră. Alegerea unui pivot în mod aleatoriu, face mai greu pentru a crea un set de date care generează O performanță (N ^ 2). „Median-de-trei“ (prima, ultima, din mijloc) este, de asemenea, o modalitate de a evita problemele. Feriți-vă de performanța relativă de comparații, deși; în cazul în care comparațiile sunt costisitoare, atunci OM3 face mai multe comparații decât alegerea (o singură valoare pivot), în mod aleatoriu. înregistrările bazei de date poate fi costisitoare pentru a compara.


Actualizare: Tragerea comentarii în răspuns.

mdkess a afirmat:

„Median de 3“ NU este prima ultima din mijloc. Alegeți trei indici aleatorii, și să ia valoarea de mijloc a acestui. Ideea este să vă asigurați că alegerea dumneavoastră pivoților nu este determinist - în cazul în care este, cel mai rău caz, datele pot fi destul de ușor generate.

La care am răspuns:

  • Analiza lui Hoare Găsiți Algoritmul cu-de- a treia partiție median (1997) de către P Kirschenhofer, H PRODINGER, C Martínez susține afirmația dumneavoastră (care 'mediana-de-trei' este de trei elemente aleatoare).

  • Există un articol descris la portal.acm.org că este vorba despre „cel mai rău caz permutare pentru Median din trei Quicksort“ Hannu Erkiö, publicat în The Computer Journal, vol 27, nr 3, 1984. [Actualizare 2012-02- 26: Am textul pentru articol . Secțiunea 2 „Algoritmul“ începe: " Prin utilizarea mediana primelor, de mijloc și ultimele elemente ale lui A [L: R], partiții eficiente în părți egale , de dimensiuni destul pot fi realizate în situații de cele mai practice. "Astfel, se discută primul-mijloc-ultima abordare OM3.]

  • Un alt articol scurt , care este interesant este de MD McIlroy, „Un Adversar Killer pentru Quicksort“ , publicat în Software-practici și de experiență, Voi. 29 (0), 1-4 (0 1999). Aceasta explică modul de a face aproape orice Quicksort se comporte quadratically.

  • AT & T Bell Labs Tech Journal, octombrie 1984 „Teoria și practica în construcția unui lucru Sortare de rutină“ , afirmă „Hoare a sugerat partiționarea în jurul medianei mai multor linii selectate aleatoriu. Sedgewick [...] a recomandat alegerea mediana primei [. ..] ultima [...] și de mijloc“. Acest lucru indică faptul că ambele tehnici de „median din trei“ sunt cunoscute în literatura de specialitate. (Actualizare 2014-11-23: Articolul pare să fie disponibil la IEEE Xplore sau de la Wiley - dacă aveți de membru sau sunt pregătiți să plătească o taxă.)

  • „Inginerie o funcție sortare“ JL Bentley si MD McIlroy, publicat in practica de software și de experiență, Vol 23 (11), noiembrie 1993 merge într - o discuție extinsă a problemelor, și ei au ales un algoritm de partiționare adaptiv bazat în parte pe mărimea setului de date. Există o mulțime de discuții de comerț-off-uri pentru diverse abordări.

  • O căutare Google pentru „mediana-of-trei“ funcționează destul de bine pentru urmărirea în continuare.

Mulțumesc de informație; Am întâlnit doar determinist „mediana-a-trei“ înainte.

Publicat 02/10/2008 la 20:42
sursa de către utilizator

voturi
1

Dacă sortați o colecție aleatoare accesibilă (cum ar fi o matrice), este general, cel mai bine pentru a alege elementul de mijloc fizic. Cu aceasta, în cazul în care matrice este gata sortate (sau aproape sortat), cele două partiții vor fi aproape chiar și veți obține cea mai mare viteză.

Dacă sortați ceva cu acces numai liniar (cum ar fi o listă înlănțuită), atunci cel mai bine este de a alege primul element, deoarece este cel mai rapid element pentru acces. Aici, cu toate acestea, în cazul în care lista este deja sortate, ești terminat - o partiție va fi întotdeauna nul, iar celălalt au tot, producând cel mai prost moment.

Cu toate acestea, pentru o listă legată, în afară de a alege orice primul, va face doar lucrurile si mai rele. Acesta va alege elementul de mijloc într-o listă afișată, ar trebui să-și intensifice prin ea pe fiecare partiție pas - adăugarea unei O (N / 2), operație care se face ori LOGN O face timpul total (1,5 N * log N) și asta dacă știm cât timp lista este înainte de a începe - de obicei, noi nu așa că ar trebui să-și intensifice tot drumul prin a le număra, apoi pas jumătatea drumului prin a găsi mijloc, apoi printr-un pas a treia oară pentru a face partiția reală: O (2,5N * log N)

Publicat 02/10/2008 la 20:42
sursa de către utilizator

voturi
1

Aceasta depinde în întregime de modul în care datele sunt sortate pentru a începe cu. Dacă credeți că va fi pseudo-aleatoare, atunci cel mai bun pariu este de a alege fie o selecție aleatoare sau alege mijloc.

Publicat 02/10/2008 la 20:46
sursa de către utilizator

voturi
16

Heh, am învățat această clasă.

Există mai multe opțiuni.
Simplu: alege primul sau ultimul element al gamei. (rău la intrare parțial sortat) O mai bună: alege elementul din mijlocul intervalului. (mai bine pe intrare parțial sortată)

Cu toate acestea, alegerea oricărui element arbitrar riscă să partiționare slab matrice de dimensiune n în două matrici de dimensiune 1 și n-1. Dacă faci destul de des că, sortarerapidă dvs. rulează riscul de a deveni O (n ^ 2).

O imbunatatire l-am vazut este alege mediana (prima, ultima, la mijlocul); În cel mai rău caz, se poate merge în continuare la O (n ^ 2), dar probabilistic, acesta este un caz rar.

Pentru cele mai multe date, alegerea prima sau ultima este suficient. Dar, dacă observați că difuzați în cel mai rău caz, scenarii de multe ori (de intrare parțial sortate), prima opțiune ar fi de a alege valoarea centrală (care este un pivot statistic bun pentru date parțial triate).

Dacă aveți în continuare probleme, du-te apoi traseul median.

Publicat 02/10/2008 la 20:46
sursa de către utilizator

voturi
8

Niciodată nu alege vreodată un pivot fix - acest lucru poate fi atacat pentru a exploata algoritmul tau cel mai rau caz O (n ^ 2) de rulare, care este doar cere probleme. Quicksort este cel mai rău caz de rulare are loc atunci când partiționarea rezultate într-o matrice de 1 element și un tablou de n-1 elemente. Să presupunem că alegeți primul element ca partiția. Dacă cineva alimentează o matrice pentru algoritm dvs., care este în ordine descrescătoare, primul pivot va fi cel mai mare, astfel încât orice altceva în matrice se va muta la stânga lui. Atunci când recursiv, primul element va fi cel mai mare din nou, așa că încă o dată ai pus totul la stânga de ea, și așa mai departe.

O tehnica mai buna este mediana-a-3 metoda, în cazul în care alegeți trei elemente la întâmplare, și alegeți mijloc. Știi că elementul pe care o alegeți nu va fi primul sau ultimul, dar, de asemenea, de teorema limită centrală, distribuirea elementului de mijloc va fi normal, ceea ce înseamnă că va tinde spre mijloc (și, prin urmare, , n lg n timp).

Dacă doriți să garanteze O (nlgn) de rulare pentru algoritmul absolut, metoda coloane-a-5 pentru a găsi mediana unei matrice se execută în O timp (n), ceea ce înseamnă că ecuația de recurență pentru sortarerapidă în cel mai rău caz va fi T (n) = O (n) (găsi mediana) + O (n) (partiție) + 2T (n / 2) (recurse la stânga și la dreapta.) Prin master teoremei, acest lucru este O (n lg n) . Cu toate acestea, factorul constant va fi foarte mare, iar în cazul în care cea mai proasta performanta caz este principala dvs. preocupare, utilizați o îmbinare de sortare în schimb, care este doar un pic mai lent decât sortarerapidă, în medie, și garantează O (nlgn) timpul (și va fi mult mai rapid decât acest sortarerapidă median lame).

Explicarea mediană a Medianele Algoritm

Publicat 25/10/2008 la 22:50
sursa de către utilizator

voturi
5

Nu încercați și să obțină prea inteligent și se combină strategiile de pivotare. Dacă combinat mediană de 3 cu pivot aleator prin alegerea mediana prima, ultima și un index aleatoriu în mijloc, atunci vei fi în continuare vulnerabile la multe dintre distribuțiile care trimit mediana de 3 pătratice (deci sa de fapt mai rău decât simplu pivot aleatoriu)

De exemplu, o distribuție de organe țeavă (1,2,3 ... N / 2..3,2,1) prima și ultima va fi atât 1 și indicele aleatoriu va fi un numar mai mare de 1, luând mediana dă 1 ( fie prima sau ultima) și veți obține o partiționare extermely dezechilibrată.

Publicat 26/10/2008 la 04:54
sursa de către utilizator

voturi
1

Este mai ușor să rupă sortarerapidă în trei secțiuni a face acest lucru

  1. Funcția de schimb sau element de date de swap
  2. Funcția de partiție
  3. Prelucrarea partițiile

Este doar puțin mai mult de o funcție inefficent lung, dar este foarte mult mai ușor de înțeles.

Cod urmează:

/* 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
  };
};
Publicat 10/03/2011 la 03:19
sursa de către utilizator

voturi
0

În mod ideal, pivotul trebuie să fie valoarea de mijloc în întreaga matrice. Acest lucru va reduce șansele de a obține cel mai rău caz de performanță.

Publicat 17/04/2013 la 15:57
sursa de către utilizator

voturi
-1

Într-o implementare cu adevărat optimizat, metoda pentru alegerea pivot ar trebui să depindă de dimensiunea matrice - pentru o gamă largă, se amortizează să-și petreacă mai mult timp alegând un pivot bun. Fără a face o analiză completă, aș ghici „mijloc de O (log (n)) elemente“ este un început bun, iar acest lucru are bonus suplimentar de a nu necesita nici o memorie suplimentară: Utilizarea coada-apel pe partiția mai mare și în- loc de partiționare, vom folosi aceeași O (log (n)) memorie suplimentară la aproape fiecare etapă a algoritmului.

Publicat 08/10/2013 la 20:50
sursa de către utilizator

voturi
0

complexitatea sortare rapidă variază foarte mult cu selectarea valorii pivot. de exemplu, dacă alegeți întotdeauna prim element ca un pivot, complexitatea algoritmului devine la fel ca și cel mai rău O (n ^ 2). aici este o metodă inteligentă de a alege pivot element- 1. alege prima, la mijlocul, ultimul element al matrice. 2. compara aceste trei numere și de a găsi numărul care este mai mare decât una și mai mică decât alte adică mediana. 3. face acest element ca element pivot.

alegerea pivotului prin această metodă se desparte matrice în aproape doua jumătate și, prin urmare, complexitatea se reduce la O (Nlog (n)).

Publicat 05/12/2013 la 06:05
sursa de către utilizator

voturi
0

În medie, mediană a 3 este bun pentru mici n. Valoarea mediană a 5 este un pic mai bine pentru a mari n. Ninther, care este „mediana a trei medianele trei“ este chiar mai bine pentru foarte mari n.

Cu cât te duci cu prelevare de probe mai bine te ca n crește, dar îmbunătățirea încetinește dramatic pe măsură ce crește mostrele. Și tu suporta aeriene de prelevare de probe și sortarea probe.

Publicat 19/10/2016 la 10:04
sursa de către utilizator

voturi
0

Vă recomandăm utilizând indexul de mijloc, deoarece poate fi calculată cu ușurință.

O puteți calcula prin rotunjire (array.length / 2).

Publicat 09/08/2017 la 01:29
sursa de către utilizator

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