Quicksort: Volba pivot

hlasů
94

Při provádění Quicksort, jedna z věcí, které musíte udělat, je vybrat si pivot. Ale když se podívám na pseudokódu jako ten dole, to není jasné, jak mám vybrat pivot. První prvek seznamu? Něco jiného?

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

Může mi někdo pomoci pochopit pojem výběru čep a zda by různé scénáře vyžadují různé strategie.

Položena 02/10/2008 v 20:37
zdroj uživatelem
V jiných jazycích...                            


13 odpovědí

hlasů
72

Vybírá náhodný pivot minimalizuje možnost, že se setkáte nejhoršího případu O (n 2 ), výkon (vždy si vybírá první nebo poslední by způsobilo nejhorší možný výkon pro téměř roztříděných či téměř reverzní roztříděných dat). Vybírá prostřední prvek by také přijatelný ve většině případů.

Také, pokud jste provádění tohoto sami, existují verze algoritmu, které pracují na místě (tj bez vytvoření dvou nových seznamů a pak je zřetězení).

Odpovězeno 02/10/2008 v 20:41
zdroj uživatelem

hlasů
47

Záleží na vašich požadavcích. Výběr čep náhodně ztěžuje vytvoření dat, který generuje výstupní výkon (N ^ 2). ‚Střední-of-tři‘ (první, poslední, uprostřed), je také způsob, jak se vyhnout problémům. Dejte si pozor na relativní výkonnosti srovnání, ačkoli; pokud vaše srovnání jsou nákladné, pak MO3 dělá více než porovnávání výběru (jedinou hodnotu otáčení) v náhodném pořadí. Záznamy databáze může být nákladné pro porovnání.


Aktualizace: Tahání připomínky v odpověď.

mdkess tvrdil:

‚Medián 3‘ není první poslední middle. Zvolit tři náhodné indexy a vzít střední hodnotu tohoto. Celý vtip je, aby se ujistil, že vaše volba otočných čepů není deterministický - pokud ano, nejhoršího případu data mohou být poměrně snadno generovány.

Na které jsem odpověděl:

  • Analýza Hoare Najít algoritmus s Median-of-tři Partition (1997) P Kirschenhofer, H Prodinger, C Martínez podporuje vaše tvrzení (že 'střední-of-tři' je tři náhodné položky).

  • Tam je článek popisuje část portal.acm.org , že je o 'nejhorším případě Permutace pro Median-of-tři quicksort' Hannu Erkiö, publikoval v The Computer Journal, Vol 27, No 3, 1984. [aktualizace 2012-02- 26: Mám text v článku . Oddíl 2 ‚algoritmus‘ začíná: " Při použití medián první, střední a poslední prvky [L: R], efektivní příčky do částí poměrně stejné velikosti může být dosaženo ve většině praktických situacích. Takto se diskusi o prvním středním poslední MO3 přístup.]

  • Další krátký článek, že je zajímavé, je MD McIlroy, „vrah protivníkem pro quicksort“ , publikoval v Software-praxe a zkušeností, sv. 29 (0), 1-4 (0, 1999). To vysvětluje, jak vytvořit téměř jakýkoliv Quicksort chová kvadraticky.

  • AT & T Bell Labs Tech Journal, říjen 1984 „Teorie a praxe v konstrukci pracovní Uspořádat Routine“ říká „Hoare navrhl rozdělení kolem mediánu několika náhodně vybraných linkách. Sedgewick [...] doporučují volbou mediánu prvního [. ..] minulý [...] a middle“. To znamená, že obě techniky pro ‚medián-of-tři‘ jsou v literatuře známé. (Aktualizace 2014-11-23: Tento článek se zdá být k dispozici na IEEE Xplore , nebo z Wiley - máte-li členství nebo jsou ochotni zaplatit poplatek).

  • ‚Strojírenská jakási funkce‘ JL Bentley a MD McIlroy, publikoval v softwaru praxe a zkušeností, Vol 23 (11), listopad 1993, jde do rozsáhlé diskuse o otázkách, a oni si vybrali adaptivní algoritmus dělení částečně založen na velikost datového souboru. Tam je hodně diskuse kompromisů pro různé přístupy.

  • Vyhledá na Googlu ‚medián-of-tři‘ funguje docela dobře pro další sledování.

Díky za informace; Jsem se setkal pouze deterministický ‚medián-of-tři‘ předtím.

Odpovězeno 02/10/2008 v 20:42
zdroj uživatelem

hlasů
1

Pokud jste třídění náhodný přístupnou sbírku (jako pole), to je obecně nejlépe vybrat fyzické prostřední položku. S tím, je-li pole je vše připraveno řazeny (nebo téměř tříděných), dva oddíly se bude blížit dokonce, a budete mít nejlepší rychlost.

Pokud máte něco, co jen s lineárním přístupem (jako propojeného-list) třídění, pak je nejlepší zvolit první položku, protože je to nejrychlejší položka přístup. Zde se však v případě, že seznam je již řazeno jste v háji - jeden oddíl bude vždy nulový a druhý mít všechno, produkovat nejhorší čas.

Nicméně, pro propojené-seznamu, vybírání nic kromě první, bude jen aby to bylo ještě horší. To vybrat prostřední položku v památkově chráněné-seznamu, měli byste mít na krok přes něj na každém kroku partition - přidáním O (/ 2 N) operace, která se provádí logn časy dělat celkový čas O (1,5 N * log N) a to pokud budeme vědět, jak dlouho tento seznam, než začneme - obvykle nemáme, takže bychom museli krok po celou dobu jejich počítat, pak krok půli cesty přes najít střed, pak krok skrz třetí čas na skutečné oddíl: o (2,5 N * log n)

Odpovězeno 02/10/2008 v 20:42
zdroj uživatelem

hlasů
1

Je to zcela závisí na tom, jak jsou řazeny vaše data pro začátek. Pokud si myslíte, že to bude pseudo-náhodné pak je nejlepší buď vybrat náhodný výběr nebo zvolte střed.

Odpovězeno 02/10/2008 v 20:46
zdroj uživatelem

hlasů
16

Heh, jen jsem učil tuto třídu.

Existuje několik možností.
Jednoduché: Vyberte první nebo poslední prvek této řady. (špatný na částečně tříděný vstupu) Better: Vyberte si položku ve středu rozsahu. (lépe částečně tříděného vstupu)

Nicméně, vybírání libovolný prvek, riskuje, že špatně rozdělování pole o velikosti n do dvou polí velikosti 1 a n-1. Pokud tak učiníte, že dost často, vaše quicksort riskuje, že se stanou O (n ^ 2).

Jeden zlepšení jsem viděl, je vybrat medián (první, poslední, MID); V nejhorším případě to může ještě jít do O (n ^ 2), ale pravděpodobnostně, jedná se o vzácný případ.

Pro většinu údajů, vybírání první nebo poslední je dostačující. Ale pokud zjistíte, že máte spuštěnou do nejhorších scénářů často (částečně řazeny vstup), první možností by bylo vybrat střední hodnotu (což je statisticky dobré pivot pro částečně tříděných dat).

Pokud jste stále běží do problémů, pak jít střední cestou.

Odpovězeno 02/10/2008 v 20:46
zdroj uživatelem

hlasů
8

Nikdy si vybrat pevný čep - to může být napadena využít algoritmu v nejhorším případě O (n ^ 2) za běhu, což je jen koleduje o malér. Quicksort nejhorší případ runtime dochází při rozdělování výsledky v jednom poli 1 elementu a jednoho pole n-1 prvků. Předpokládejme, že si vyberete první prvek jako svůj oddíl. Pokud se někdo krmí pole do svého algoritmu, který je v sestupném pořadí, budou vaše první pivot být největší, takže vše, co v poli se přesune do nalevo od něj. Pak, když jste recurse, první prvek bude opět největší, takže ještě jednou dáte všechno nalevo od něj, a tak dále.

Lepší metoda je střední-of-3 metoda, kde si vybrat tři prvky náhodně, a zvolte střed. Víte, že prvek, který si vyberete nebude první ani poslední, ale také tím, že centrální limitní věta, rozdělení středního prvku bude normální, což znamená, že budete mít sklon směrem ke středu (a tudíž , n lg n času).

Pokud si absolutně chcete zaručit O (nlgn) runtime pro algoritmus, metoda pro nalezení mediánu pole sloupce-of-5 běží v O (n) čas, což znamená, že opakování rovnice pro quicksortu v nejhorším případě bude být T (n) = o (n) (zde medián) + o (n) (blok) + 2T (n / 2) (recurse vlevo a vpravo). masterem věty, to je o (n lg n) , Nicméně, konstantní faktor bude obrovská, a pokud se nejhorší případ výkon je váš hlavní náplní, použijte sloučení sort místo, což je jen o trochu pomalejší než quicksortu v průměru, a zaručuje O (nlgn) čas (a bude mnohem rychlejší než tento lame střední quicksortu).

Vysvětlení Median mediánové algoritmu

Odpovězeno 25/10/2008 v 22:50
zdroj uživatelem

hlasů
5

Nesnažte se dostat příliš chytrý a kombinovat otočné strategie. Máte-li v kombinaci medián 3 s náhodným čepu výběrem medián první, poslední a náhodného index ve středu, pak budete i nadále zranitelné vůči mnoha distribucí, které vysílají medián 3 kvadratická (takže je ve skutečnosti horší než prostý náhodný čep)

Například distribuční varhany (1,2,3 ... N / 2..3,2,1) první a poslední budou oba 1 a náhodná index bude nějaké číslo větší než 1, přičemž medián udává 1 ( buď první nebo poslední) a dostanete extermely nevyvážené dělení.

Odpovězeno 26/10/2008 v 04:54
zdroj uživatelem

hlasů
1

Je snazší rozbít quicksort do tří sekcí to dělá

  1. Výměna nebo výměna datový prvek Funkce
  2. Funkce partition
  3. Zpracování oddílů

Je to jen o něco více než inefficent jedné dlouhé funkcí, ale je mnohem srozumitelnější.

Kód následujícím způsobem:

/* 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
  };
};
Odpovězeno 10/03/2011 v 03:19
zdroj uživatelem

hlasů
0

V ideálním případě by měl být otočný střední hodnota v celé pole. Tím se sníží šance na získání nejhorší výkon.

Odpovězeno 17/04/2013 v 15:57
zdroj uživatelem

hlasů
-1

Ve skutečně optimalizované realizace, způsob výběru pivot by měla záviset na velikosti pole - pro velké pole, vyplatí se věnovat více času výběru dobrého pivot. Aniž by dělali celkovou analýzu, řekl bych „střed O (log (n)) prvky“ Je to dobrý začátek, a to má bonus nevyžaduje žádné přídavné paměti: Použití ocas-volání na větší oddíl a in- místo partitioning, používáme stejný o (log (n)) přídavné paměti na téměř každé etapy algoritmu.

Odpovězeno 08/10/2013 v 20:50
zdroj uživatelem

hlasů
0

Složitost quicksort se značně mění s výběrem otočného hodnoty. Například, pokud jste vždy zvolit první prvek jako pivot, složitost algoritmu stává stejně jako nejhůře O (n ^ 2). Zde je chytrý způsob, jak vybrat pivot prvek- 1. zvolit první, střední, poslední prvek pole. 2. porovnat tyto tři čísla a najít číslo, které je větší než jedna a menší než ostatní, tj medián. 3., aby tento prvek jako otočný prvek.

výběru čep podle tohoto způsobu se rozštěpí pole v téměř dvě poloviny, a tím snižuje složitost na O (nlog (n)).

Odpovězeno 05/12/2013 v 06:05
zdroj uživatelem

hlasů
0

V průměru Median 3 je dobrá pro malé n. Medián 5 je o něco lepší pro větší n. Ninther, což je „medián tří mediánové tři“ je ještě lepší pro velké n.

Čím vyšší jdete s vzorkování, tím lépe se dostanete během zvýšení n, ale zlepšení dramaticky zpomalí, jak si zvýšit vzorky. A roamingovými režii odběru a třídění vzorků.

Odpovězeno 19/10/2016 v 10:04
zdroj uživatelem

hlasů
0

I doporučujeme používat střední index, protože se dá jednoduše vypočítat.

Si můžete spočítat jej zaoblením (Array.length / 2).

Odpovězeno 09/08/2017 v 01:29
zdroj uživatelem

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