Hajoita ja hallitse (divide and conquer) Pikalajittele n-alkioinen taulukko 1. Divide: Jaetaan taulukko kahdeksi alitaulukoksi tukialkion (pivot) x suhteen: 2. Conqueror: Lajitellaan alitaulukot rekursiivisesti 3. Yhdistäminen: triviaali x xx xx
Animaatio orters/quicksort.html
Osiointi 55 55
Yksinkertaisin versio void pikalajittelu1(alkio a[], int l, int r){ int i, m, x=a[l]; if (l >= r) return; m = l; for (i = l+1; i <= r; i++) if (a[i] < x) vaihda(a, ++m, i); vaihda(a, l, m); pikalajittelu1(a, l, m-1); pikalajittelu1(a, m+1, r); } xx xx?x lmir enintään yksi alkio => palaa x xx xx mlr x xx xx lmr ensimmäinen alkio on tukialkio
Kaikki alkiot samoja 55 l,mr Taulukon jako on hyvin epätasainen: toiseen alitaulukkoon kuuluu kaikki muut alkiot paitsi tukialkio.
Kaksisuuntainen osiointi void pikalajittelu3(alkio a[], int l, int r){ int i, j; alkio x; if (l >= r) return; x = a[l]; i = l; j = r+1; for (;;) { do i++; while (i <= r && a[i] < x); do j--; while (a[j] > x); if (i > j) break; vaihda(a, i, j); } vaihda(a, l, j); pikalajittelu3(a, l, j-1); pikalajittelu3(a, j+1, r); } xx xx ? x li j r enintään yksi alkio => palaa Pysähdytään yhtäsuuriin elementteihin
Alkiot nousevassa järjestyksessä l,mr Taulukon jako on hyvin epätasainen: toiseen alitaulukkoon kuuluu kaikki muut alkiot paitsi tukialkio.
Satunnaistaminen + pienten alitaulukoiden lisäyslajittelu int cutoff = 50; void pikalajittelu4(alkio a[], int l, int r){ int i, j; alkio t, temp; if (r - l < cutoff) return; vaihda(a, l, randint(l, r)); x = a[l]; i = l; j = r+1; for (;;) { do i++; while (i <= r && a[i] < x); do j--; while (a[j] > x); if (i > j) break; vaihda(a, l, j); } vaihda(a, l, j); pikalajittelu4(a, l, j-1); pikalajittelu4(a, j+1, r); } pieni taulukko => palaa Ohjelman päättyessä taulukko a:n sisältö ei ole lajiteltuna, vaan se on ryhmitelty pieniin satunnaisesti järjestettyihin arvoihin. Kukin ryhmä sisältää pienempiä arvoja kuin sen oikealla puolella olevat. Lajittelu: pikalajittelu4(a, l, r); lisayslajittelu3(a, l, r); vaihdetaan satunnainen alkio tukialkioksi
Kolmivaiheinen osiointi Tehokas runsaasti samoja avaimia sisältävässä tapauksessa
Algoritmin kompleksisuus Huonoin tapaus: toiselle puolelle jää N-1 alkiota ja toiselle 0 => O(N 2 ) Paras tapaus: molemmille puolille jää yhtä monta alkiota => O(N log N) Myös keskimääräinen kompleksisuus on O(N log N)
Tukialkion valinta 1. Valitaan vakiopaikasta, esim. taulukon ensimmäinen. Toimii hyvin satunnaiselle syötteelle. Melkein järjestetylle syötteelle jako on erittäin epätasainen. 2. Valitaan tukialkioksi ensimmäisen, keskimmäisen ja viimeisen alkion mediaani. 3. Valitaan tukialkio satunnaisesti. Erittäin todennäköisesti osittelu on tasainen.
Valitaan k:ksi pienin alkio rekursiivisesti void valitse_rekursiivisesti(alkio a[], int l, int r, int k) { int i; if(r <= l) return; i = osioi(a, l, r); if(i > k) valitse_rekursiivisesti(a, l, i - 1, k); if(i < k) { valitse_rekursiivisesti(a, i + 1, r, k); } k:s alkio löytyy taulukosta kohdasta a[k-1] vaikkei taulukkoa ole kokonaan lajiteltukaan
Valitaan k:ksi pienin alkio iteratiivisesti void valitse_iteratiivisesti(alkio a[], int l, int r, int k) { int i; while(r > l) { i = osioi(a, l, r); if(i >= k) r = i - 1; if(i <= k) l = i + 1; } k:s alkio löytyy taulukosta kohdasta a[k-1] vaikkei taulukkoa ole kokonaan lajiteltukaan