Šis pavyzdys parodo savavališko predikato naudojimą funkcinėje kalboje.
Linksmas greitas rūšiavimas lt lst = tegul val rec rūšiuoti = fn => | (x::xs) => tegul val (kairėje, dešinėje) = Sąrašo skaidinys (fn y => lt (y, x)) xs rūšiuoti kairėje @ x:: rūšiuoti dešinėje pusėje rūšiuoti lst pabaigoje
TCL# Funkcija pasirenka posąrašį iš sąrašo naudodama sąlygą proc lfind (duomenų arg sąlyga) ( set foo foreach item $data ( set $arg $item if () (lappend foo $item) ) return $foo ) # Pats rūšiavimas proc QRūšiuoti duomenis (nustatyti rezultatą () if (!= 0) (nustatyti patikrinimo rinkinio rezultatą [ concat \ ] \ \ ]] ) return $result ) Perl
@out=(5,2,7,9,2,5,67,1,5,7,-8,5,0); sub sortQ( my($s, $e) = @_; mano $m = $s - 1; for($s..$e - 1)( if($out[$_] lt $out[$e ])( ++$m; ($out[$m], $out[$_]) = ($out[$_], $out[$m]); ) ) ++$m; ($out [$m], $out[$e]) = ($out[$e], $out[$m]); rūšiuotiQ($s, $m-1), jei $s< $m-1;
sortQ($m+1, $e) if $m+1 < $e;
}
sortQ(0, $#out);
F#
Tegul rec Quicksort = funkcija -> | h::t -> greitas rūšiavimas ([ x in t, kai x<=h ->x]) @ [h] @ greitas rūšiavimas ([ x in t, kai x>h -> x]);;
OCaml
Tegul rec qsort l=atitinka l su -> |a::b-> (qsort (List.filter ((>=) a) b) lt) @ [a] @ (qsort (List.filter ((<) a) b));;
Erlang
Qsort() -> ; qsort() -> qsort() ++ [H] ++ qsort().
D
Masyvo qsort(masyvas)(masyvas _a) ( slapyvardis(masyvo.init) _type; masyvo filtras(bool delegate(_type) dg, masyvas a)( masyvo buferis = null; foreach(value; a) ( if(dg(value) ))( buferis ~= reikšmė; ) ) grąžinti buferį; ) if(_a.length<= 1) {
return _a;
}
else {
return qsort(filter((_type e){ return _a >= e; ), _a)) ~ _a ~ qsort(filter((_type e)( return _a< e; }, _a));
}
}
Trumpesnė versija naudojant standartinę Phobos biblioteką:
Importuoti std.algoritmą; T_qsort3(T)(T a) ( if(a.length<= 1)
return a;
else
return _qsort3(a.filter!(e =>a >= e).masyvas) ~ a ~ _qsort3(a.filter!(e => a< e).array);
}
Scala
Numatytasis qsort](sąrašas: Sąrašas[A]): Sąrašas[A] = sąrašo atitiktis ( didžiosios raidės pavadinimas::uodega => ( qsort(uodegos filtras(head>=)) ::: head:: qsort(uodegos filtras (galva<))
}
case _ =>sąrašas; )
Kitas variantas:
Numatytasis rūšiavimas(xs: Masyvas): Masyvas = ( if (xs.length<= 1) xs
else {
val pivot = xs(xs.length / 2)
Array.concat(sort(xs filter (pivot >)), xs filtras (pivot ==), rūšiuoti (xs filtras (sukti<)))
}
}
Clojure
Tingus įgyvendinimas:
(defn qsort [] (letfn [(f [g] (qsort (filtras #(g % x) xs))))] (kai x (tinginys-katė (f)<) [x] (f >=)))))
Shen / Qi II
(apibrėžti filtrą ((A --> loginis) --> (sąrašas A) --> (sąrašas A)) _ -> T? -> (pridėti [A] (filtras T? B)) kur (T? A ) T? [_|B] -> (filtras T? B)) (apibūdinti q-sort ((sąrašo numeris) --> (sąrašo numeris)) -> -> (pridėti (q-rūšiuoti (filtras (> A)) ) )) [A] (q-rūšiavimas (filtras ()< A) ))))
VB.NET
Sprendžiant iš testų, burbulų rūšiavimas 5000 užtrunka 8 su puse karto ilgiau nei qSort
Sub Swap (ByRef Val1, ByRef Val2) Dim Proc = Val1 Val1 = Val2 Val2 = Proc pabaigos subfunkcijos skaidinys (ByRef a() Kaip sveikasis skaičius, ByVal kairėje kaip sveikasis skaičius, ByVal dešinėje kaip sveikasis skaičius, ByRef sukimasis kaip sveikasis skaičius) Dim i Dim piv Pritemdyta saugykla piv = a(suvestis) Sukeisti(a(dešinė - 1), a(suvestis)) parduotuvė = kairė For i = kairė Į dešinę - 2 Jei a(i)<= piv Then
Swap(a(store), a(i))
store = store + 1
End If
Next
Swap(a(right - 1), a(store))
Return store
End Function
Function getpivot(ByRef a() As Integer, ByVal left As Integer, ByVal right As Integer)
Return New System.Random().Next(left, right - 1)
End Function
Sub quicksort(ByRef a() As Integer, ByVal left As Integer, ByVal right As Integer)
Dim pivot As Integer
If right - left >1 Tada sukimas = getpivot(a, kairėn, dešinėn) susukimas = skaidinys(a, kairėn, dešinėn, suktis) quicksort(a, left, pivot) quicksort(a, pivot + 1, right) End If End Sub Sub qSort(ByVal) a() Kaip sveikasis skaičius) Dim i Dim ii Kai i = 0 Iki a.Length() - 1 ii = Nauja sistema.Atsitiktinis().Next(0, a.Length() - 1) Jei i<>ii Tada Sukeisti(a(i), a(ii)) Pabaiga, jei kitas greitas rūšiavimas(a, 0, a.Length()) Pabaigos sub
Funkcijos skambutis:
QSort (rūšiuojamo masyvo pavadinimas)
PHP
Funkcijos greitas rūšiavimas (& $masyvas , $l = 0, $r = 0 ) ( if($r === 0) $r = count($masyvas)-1; $i = $l; $j = $r; $x = $masyvas[($l + $r) / 2]; do ( while ($masyvas[$i]< $x) $i++;
while ($array[$j] >$x) $j--; jei ($i<= $j) {
if ($array[$i] >$masyvas[$j]) list($masyvas[$i], $masyvas[$j]) = masyvas($masyvas[$j], $masyvas[$i]); $i++; $j--; ) ) o ($i<= $j);
if ($i < $r) quicksort ($array, $i, $r);
if ($j >$l) greitas rūšiavimas ($masyvas, $l, $j); )
Integruota kalba 1C 8.*
Čia yra rūšiavimo algoritmas, naudojant „Verčių sąrašo“ tipo objekto pavyzdį, tačiau jį galima modifikuoti, kad jis veiktų su bet kokiu objektu; norėdami tai padaryti, turite pakeisti „CompareValues“, „GetValue“ kodą. , „SetValue“ veikia atitinkamai.
Funkcija Lyginti Vertes(reikšmė1, Reikšmė2) Jei Reikšmė1>Vertė2 Tada grąžina 1; endIf; Jei reikšmė1<Знач2 Тогда
Возврат -1;
КонецЕсли;
Возврат 0;
КонецФункции
Функция ПолучитьЗначение(Список, Номер)
Возврат Список.Получить(Номер-1).Значение;
КонецФункции
Процедура УстановитьЗначение(Список, Номер, Значение)
Список[Номер-1].Значение = Значение;
КонецПроцедуры
Процедура qs_0(s_arr, first, last)
i = first;
j = last;
x = ПолучитьЗначение(s_arr, Окр((first + last) / 2, 0));
Пока i <= j Цикл
Пока СравнитьЗначения(ПолучитьЗначение(s_arr, i), x)=-1 Цикл
i=i+1;
КонецЦикла;
Пока СравнитьЗначения(ПолучитьЗначение(s_arr, j), x)=1 Цикл
j=j-1;
КонецЦикла;
Если i <= j Тогда
Если i < j Тогда
к=ПолучитьЗначение(s_arr, i);
УстановитьЗначение(s_arr, i, ПолучитьЗначение(s_arr, j));
УстановитьЗначение(s_arr, j, к);
КонецЕсли;
i=i+1;
j=j-1;
КонецЕсли;
КонецЦикла;
Если i < last Тогда
qs_0(s_arr, i, last);
КонецЕсли;
Если first < j Тогда
qs_0(s_arr, first,j);
КонецЕсли;
КонецПроцедуры
Процедура Сортировать(Список, Размер="", Первый="", Последний="")
Если Не ЗначениеЗаполнено(Первый) Тогда
Первый=1;
КонецЕсли;
Если НЕ ЗначениеЗаполнено(Последний) Тогда
Последний=Размер;
КонецЕсли;
qs_0(Список, Первый, Последний);
КонецПроцедуры
Turbo Basic 1.1
DEF FN QSORT(ŽEMAS, AUKŠTAS) VIETINIS I,J,X,TEMP.J=AUKŠTAS X=Y[(ŽEMAS+AUKŠTAS)/2] DO WHILE Y[I] X:J=J-1:WEND, JEI I<=J THEN
TEMP=Y[I]
Y[I]=Y[J]
Y[J]=TEMP
I=I+1
J=J-1
END IF
LOOP WHILE I<=J
IF LOW
Funkcijos FN QSORT(LOW, HIGH) iškvietimo pavyzdys, įvesties ir išvesties duomenys DIM Y masyve
LOW = N1 AUKŠTAS = N2 F = FN QSORT (žemas, AUKŠTAS)
Verta paminėti, kad greitas rūšiavimas gali būti neveiksmingas masyvuose, kuriuos sudaro nedidelis elementų skaičius, todėl dirbant su jais protingiau šio metodo atsisakyti. Apskritai, algoritmas yra nestabilus, o rekursijos naudojimas neteisingai parašytame kode gali sukelti krūvos perpildymą. Tačiau, nepaisant šių ir kai kurių kitų trūkumų, greitas rūšiavimas vis dar yra vienas efektyviausių ir dažniausiai naudojamų būdų.
Rašant šį straipsnį buvo naudojami atvirieji šaltiniai internete:
Jei programuojate ir jūsų kodas neapsiriboja skaičiuotuvo rašymu, ne kartą susidursite arba susidūrėte su poreikiu rūšiuoti tą ar kitą duomenų masyvą. Yra daug būdų rūšiuoti. Šiame straipsnyje išanalizuosime pagrindinius ir sutelksime dėmesį į greitą rūšiavimą.
Greito rūšiavimo sąvoka
Greitas rūšiavimas – Greitas rūšiavimas arba qsort. Pavadinimas aiškiai parodo, kas tai yra ir kodėl. Bet jei tai neaišku, tai yra greito masyvo rūšiavimo algoritmas; algoritmo efektyvumas yra vidutiniškai O(n log n). Ką tai reiškia? Tai reiškia, kad vidutinė algoritmo veikimo trukmė didėja ta pačia trajektorija kaip ir šios funkcijos grafikas. Kai kurios populiarios kalbos turi integruotas bibliotekas su šiuo algoritmu, o tai jau rodo, kad jis yra labai efektyvus. Tai yra tokios kalbos kaip Java, C++, C#.
Algoritmas
Greitojo rūšiavimo metodas naudoja rekursiją ir strategiją „skaldyk ir valdyk“.
1. Masyve ieškoma tam tikro atskaitos elemento, dėl paprastumo geriau paimti centrinį, bet jei norite dirbti su optimizavimu, turėsite išbandyti įvairias parinktis.
2. Į kairę nuo atramos ieškome didesnio už atramą elemento, dešinėje - mažesnio už atramą, tada juos sukeičiame. Tai darome tol, kol maksimumas dešinėje bus mažesnis nei kairėje esantis minimumas. Taigi pradžioje metame visus mažus elementus, o pabaigoje – didelius.
3. Šį algoritmą rekursyviai pritaikome kairiajai ir dešiniajai mūsų algoritmo dalims, tada vėl ir vėl, kol pasiekiame vieną elementą arba tam tikrą elementų skaičių. Koks yra šis elementų skaičius? Yra dar vienas būdas optimizuoti šį algoritmą. Kai išrūšiuota dalis tampa maždaug lygi 8 arba 16, tada ją galima apdoroti įprastiniu rūšiavimu, pavyzdžiui, burbuliniu rūšiavimu. Taip padidinsime savo algoritmo efektyvumą, nes Jis neapdoroja mažų masyvų taip greitai, kaip norėtume.
Tokiu būdu visas masyvas bus apdorojamas ir rūšiuojamas. Dabar aiškiai išstudijuokime šį algoritmą
Greito rūšiavimo efektyvumas
Ar greitasis rūšiavimas yra greičiausias rūšiavimo algoritmas? Tikrai ne. Dabar atsiranda vis daugiau rūšiavimo, šiuo metu greičiausias rūšiavimas yra Timsort, itin greitai veikia masyvams, kurie iš pradžių buvo surūšiuoti kitaip. Tačiau nepamirškite, kad greito rūšiavimo metodas yra vienas iš paprasčiausių rašymo būdų; tai labai svarbu, nes paprastai įprastam projektui tereikia paprasto rašymo, o ne didžiulio algoritmo, kurio negalėtumėte parašyti. save. Timsort taip pat nėra pats sudėtingiausias algoritmas, tačiau jis tikrai negaus paprasčiausio titulo.
Algoritmo įgyvendinimas
Na, mes pasiekėme „skaniąją“ dalį. Dabar pažiūrėkime, kaip šis algoritmas įgyvendinamas. Kaip minėta anksčiau, tai nėra labai sunku įgyvendinti, greičiau net paprasta. Tačiau mes vis tiek išsamiai išanalizuosime kiekvieną savo kodo veiksmą, kad suprastumėte, kaip veikia greitas rūšiavimas.
Mūsų metodas vadinamas greituoju rūšiavimu. Jis vykdo pagrindinį algoritmą, į kurį perduodame masyvą, pirmąjį ir paskutinįjį jo elementus. Pirmuosius ir paskutinius surūšiuoto segmento elementus saugome kintamuosiuose i ir k, kad šie kintamieji nepakeistų, nes mums jų reikia. Tada patikriname atstumą tarp pirmo ir paskutinio patikrinto: ar jis didesnis ar lygus vienetui? Jei ne, tada mes pasiekėme centrą ir turime išeiti iš šio segmento rūšiavimo, o jei taip, tada tęsiame rūšiavimą.
Tada pirmąjį rūšiuojamo segmento elementą imame kaip atraminį elementą. Darome kitą ciklą, kol pasieksime centrą. Jame darome dar du ciklus: pirmasis - kairiajai daliai, o antrasis - dešinei. Juos atliekame tol, kol yra sąlygą atitinkančių elementų arba kol pasiekiame atraminį elementą. Tada, jei minimalus elementas vis dar yra dešinėje, o maksimalus elementas yra kairėje, mes juos sukeičiame. Ciklui pasibaigus, pakeičiame pirmąjį elementą ir atskaitos elementą, jei atskaitos elementas yra mažesnis. Tada mes rekursyviai atliekame savo algoritmą dešiniajai ir kairiajai masyvo dalims ir tęsiame tol, kol pasieksime 1 elemento ilgio skyrių. Tada visi mūsų rekursiniai algoritmai grįš ir mes visiškai išeisime iš rūšiavimo. Taip pat apačioje yra apsikeitimo metodas - visiškai standartinis masyvo rūšiavimo būdas pakeičiant. Kad nerašytume pakeičiančių elementų kelis kartus, mes rašome vieną kartą ir keičiame elementus šiame masyve.
Apibendrinant galima teigti, kad pagal kokybės ir sudėtingumo santykį greitasis rūšiavimas užima pirmaujančias pozicijas tarp visų algoritmų, todėl tikrai turėtumėte įsidėmėti šį metodą ir prireikus jį panaudoti savo projektuose.
apibūdinimas
Funkcija qsort surūšiuoja masyvo elementų skaičių, į kuriuos nukreipia pirmasis žymeklis. Kiekvienam masyvo elementui suteikiamas dydis baitais, kuris perduodamas per dydžio parametrą. Paskutinis funkcijos qsort parametras yra lyginamoji rodyklė į palyginimo funkciją, kuri naudojama elementų tvarkai surūšiuotame masyve nustatyti.
Šios funkcijos naudojamas rūšiavimo algoritmas lygina reikšmių poras, iškviesdamas nurodytą palyginimo funkciją, su dviem rodyklėmis į masyvo elementus.
Ši funkcija negrąžina jokios reikšmės, bet pakeičia masyvo, į kurį pirmiausia nurodė, turinį. Taigi masyvo elementai užima naujas vietas pagal rūšiavimo tvarką.
Galimybės:
- Pirmas
Rodyklė į pirmąjį rūšiuojamo masyvo elementą.
- numerį
Elementų skaičius rūšiuojamajame masyve, į kurį nukreipta pirmoji žymeklis.
- dydis
Vieno masyvo elemento dydis baitais.
- lyginamoji priemonė
Funkcija, lyginanti du elementus. Funkcija turi turėti tokį prototipą:
int funccmp(const void * val1, const void * val2); Funkcija turi užimti du parametrus – rodykles į masyvo elementus, kurių tipas void*. Šie parametrai turi būti perduoti tam tikriems duomenų tipams. Šios funkcijos grąžinimo vertė turi būti neigiama, nulis arba teigiama. Jei val1 yra mažesnis, lygus arba didesnis nei val2 , funkcija turi atitinkamai grąžinti neigiamą reikšmę, nulį arba teigiamą reikšmę.
Grąžinimo vertė
Pavyzdys: programos šaltinio kodas
//funkcijos qsort naudojimo pavyzdys #include #įtraukti int vektorius = ( 14, 10, 11, 19, 2, 25 ); int palyginti(const void * x1, const void * x2) // masyvo elementų palyginimo funkcija ( return (*(int*)x1 - *(int*)x2); // jei atimties rezultatas yra 0, tada skaičiai lygūs,< 0: x1 < x2; >0: x1 > x2 ) int main () ( qsort(vector, 6, sizeof(int), palyginti); // surūšiuoti skaičių masyvą, skirtą (int ix = 0; ix< 6; ix++)
std::cout << vector << " ";
return 0;
}
Trumpas algoritmo aprašymas
- pasirinkite elementą, vadinamą pagalbiniu elementu.
- palyginkite visus kitus elementus su etaloniniu, remdamiesi palyginimu, aibę padalinkite į tris - „mažesnis už etaloninį“, „lygus“ ir „didesnis“, išdėliokite juos tvarka mažesnis-lygus-didesnis.
- pakartokite rekursyviai „mažesniam“ ir „didesniam“.
Pastaba: praktikoje surūšiuotas rinkinys paprastai skirstomas ne į tris, o į dvi dalis: pavyzdžiui, „mažesnis už atskaitą“ ir „lygus ir didesnis“. Bendru atveju šis metodas pasirodo esąs efektyvesnis, nes tokiam padalijimui atlikti pakanka vieno praėjimo per surūšiuotą rinkinį ir vieno apsikeitimo tik kai kuriais pasirinktais elementais.
Algoritmas
„Quicksort“ naudoja „skaldyk ir valdyk“ strategiją. Algoritmo žingsniai yra šie:
- Masyve pasirenkame kokį nors elementą, kurį iškviesime atraminis elementas. Algoritmo teisingumo požiūriu atskaitos elemento pasirinkimas yra abejingas. Algoritmo efektyvumo didinimo požiūriu reikėtų pasirinkti medianą, tačiau be papildomos informacijos apie rūšiuojamus duomenis jos gauti dažniausiai neįmanoma. Gerai žinomos strategijos: nuolat rinkitės tą patį elementą, pavyzdžiui, vidurinį arba paskutinį pozicijoje; pasirinkite elementą su atsitiktinai parinktu indeksu.
- Operacija atskyrimas masyvas: pertvarkyti masyvą taip, kad visi elementai, mažesni už atskaitos elementą arba jam lygūs, būtų jo kairėje, o visi elementai, didesni už atskaitos elementą, būtų dešinėje. Įprastas veikimo algoritmas:
- Du indeksai – l ir r yra lygūs atitinkamai padalytos masyvo minimaliam ir maksimaliam indeksui.
- Apskaičiuojamas atskaitos elemento m indeksas.
- Indeksas l nuosekliai didinamas tol, kol l-asis elementas viršija atskaitos elementą.
- Indeksas r nuosekliai mažinamas, kol r-asis elementas yra mažesnis arba lygus atskaitos elementui.
- Jei r = l – rastas masyvo vidurys – padalijimo operacija baigta, abu indeksai nurodo atskaitos elementą.
- Jeigu l< r - найденную пару элементов нужно обменять местами и продолжить операцию разделения с тех значений l и r, которые были достигнуты. Следует учесть, что если какая-либо граница (l или r) дошла до опорного элемента, то при обмене значение m изменяется на r-й или l-й элемент соответственно.
- Rekursyviai išdėstome pogrupius, esančius atskaitos elemento kairėje ir dešinėje.
- Rekursijos pagrindas yra aibės, susidedančios iš vieno ar dviejų elementų. Pirmasis grąžinamas pradine forma, antrajame, jei reikia, rūšiavimas sumažinamas iki dviejų elementų pertvarkymo. Visi tokie segmentai jau užsakomi padalijimo proceso metu.
Kadangi kiekvienoje iteracijoje (kiekviename kitame rekursijos lygyje) apdorojamo masyvo segmento ilgis sumažėja bent vienu, galutinis rekursijos atšakas visada bus pasiektas ir apdorojimas bus garantuotas.
Įdomu tai, kad Hoare'as sukūrė šį metodą, susijusį su mašininiu vertimu: faktas yra tas, kad tuo metu žodynas buvo saugomas magnetinėje juostoje, o jei tekste išdėstysite visus žodžius, jų vertimus bus galima gauti vienu juostos paleidimu. Algoritmą Hoare'as sugalvojo būdamas Sovietų Sąjungoje, kur Maskvos universitete studijavo kompiuterinį vertimą ir kūrė rusų-anglų kalbų sąsiuvinį (sakoma, kad šį algoritmą jis girdėjo iš rusų studentų).
//algoritmas Java public static void qSort(int A, int low, int high) ( int i = žemas; int j = didelis; int x = A[ (žemas+ aukštas) / 2 ] ; do ( while (A[ i])<
x)
++
i;
while
(A[
j]
>x) -- j; jeigu aš<=
j)
{
int
temp =
A[
i]
;
A[
i]
=
A[
j]
;
A[
j]
=
temp;
i++;
j--;
}
}
while
(i <
j)
;
if
(low <
j)
qSort(A, low, j)
;
if
(i <
high)
qSort(A, i, high)
;
}
|
//algoritmas Paskalio kalba procedūra qSort(var ar: realaus masyvas ; žemas, aukštas: sveikasis skaičius ) ; var i, j: sveikasis skaičius ; m, wsp: realus ; start i: = žemas; j: = didelis; m: = ar[ (i+ j) div 2 ] ; kartoti kol (ar[i] m) daryti j: = j-1; jeigu aš<=
j)
then
begin
wsp:
=
ar[
i]
;
ar[
i]
:
=
ar[
j]
;
ar[
j]
:
=
wsp;
i:
=
i+
1
;
j:
=
j-
1
;
end
;
until
(i >j) ; jei (žemas
|
//algoritmas Visual Basic kalba
//pirmojo skambučio metu 2-asis argumentas turi būti lygus 1
//3-asis argumentas turi būti lygus masyvo elementų skaičiui Sub qSort(ByVal ar() Kaip double, ByVal low As Integer , ByVal high As Integer ) Dim i, j Kaip sveikasis skaičius Dim m, wsp Kaip double i = žemas j = didelis m = ar((i + j) \ 2 ) Daryti iki i > j Daryti, kol ar(i)< m
i +=
1
Loop
Do
While
ar(j)
>m j - = 1 kilpa Jei (t. y<=
j)
Then
wsp =
ar(i)
ar(i)
=
ar(j)
ar(j)
=
wsp
i +=
1
j -=
1
End
If
Loop
If
(low < j)
Then
qSort(ar,
low,
j)
If
(i < high)
Then
qSort(ar,
i,
high)
End
Sub
|
Efektyvumo ženklas
„QuickSort“ yra žymiai patobulinta tiesioginio mainų rūšiavimo algoritmo versija (jo variantai žinomi kaip „Bubble Sort“ ir „Shaker Sort“), žinoma, be kita ko, dėl mažo efektyvumo. Esminis skirtumas yra tas, kad po kiekvieno praėjimo elementai yra suskirstyti į dvi nepriklausomas grupes. Įdomus faktas: patobulinus neefektyviausią tiesioginio rūšiavimo metodą, buvo gautas efektyvus patobulintas metodas.
- Geriausias atvejis.Šiam algoritmui geriausias atvejis yra, jei kiekvienoje iteracijoje kiekviena pogrupė yra padalinta į dvi vienodo dydžio matricas. Dėl to greitojo rūšiavimo atliktų palyginimų skaičius būtų lygus rekursinės išraiškos C N = 2C N/2 +N reikšmei, kuri aiškiai duoda maždaug N log N palyginimų. Tai suteiktų mažiausiai laiko rūšiavimui.
- Vidutinis. Suteikia vidutiniškai O( nžurnalas n) keitimai užsakymo metu n elementai. Realiai kaip tik tokia situacija dažniausiai susiklosto, kai elementai išdėstomi atsitiktine tvarka ir atskaitos elementas pasirenkamas iš masyvo vidurio arba atsitiktinai.
Praktiškai (tuo atveju, kai mainai yra brangesnė operacija nei palyginimai), greitas rūšiavimas yra žymiai greitesnis nei kiti algoritmai su O( n lg n), dėl to, kad vidinė algoritmo kilpa gali būti efektyviai įgyvendinta beveik bet kurioje architektūroje. 2C N/2 padengia dviejų gautų pogrupių rūšiavimo išlaidas; N yra kiekvieno elemento apdorojimo naudojant vieną ar kitą žymeklį kaina. Taip pat žinoma, kad apytikslė šios išraiškos reikšmė yra C N = N log N.
- Blogiausiu atveju. Akivaizdu, kad blogiausias atvejis būtų toks, kai kiekviename etape masyvas būtų padalintas į išsigimusią vieno atskaitos elemento pogrupį ir visų kitų elementų pogrupį. Taip gali nutikti, jei kiekviename etape kaip atskaitos elementas pasirenkamas mažiausias arba didžiausias visų apdorotų elementų.
Blogiausiu atveju suteikia O( n²) mainai. Tačiau keitimų skaičius ir atitinkamai veikimo laikas nėra didžiausias jo trūkumas. Blogiausia tai, kad tokiu atveju rekursijos gylis vykdant algoritmą sieks n, o tai reikš n kartų išsaugoti masyvo padalijimo procedūros grąžinimo adresą ir vietinius kintamuosius. Esant didelėms n reikšmėms, blogiausiu atveju gali pritrūkti atminties, kol veikia algoritmas. Tačiau naudojant daugumą realių duomenų galima rasti sprendimus, kurie sumažintų tikimybę, kad prireiks kvadratinio laiko.
Patobulinimai
- Atsitiktinai pasirinkus atskaitos elementą iš tam tikro diapazono, blogiausias atvejis tampa labai mažai tikėtinas ir numatomas rūšiavimo algoritmo vykdymo laikas yra O( n lg n).
- Pasirinkite vidurį iš trijų (pirmasis, vidurinis ir paskutinis) kaip atraminį elementą. Šis pasirinkimas taip pat nukreiptas prieš blogiausią atvejį.
- Kad blogiausiu atveju (arba artėjant prie jo) nepasiektumėte pavojingo rekursijos gylio, galima modifikuoti algoritmą, kad būtų pašalinta viena rekursijos atšaka: užuot iškvietus skaidymo procedūrą rekursyviai abiejuose rastuose pogrupiuose, padalinus masyvą, rekursinis iškvietimas atliekamas tik mažesniame pogrupyje, o didesnis apdorojamas cikle per tą patį procedūros iškvietimą. Kalbant apie efektyvumą, vidutiniu atveju skirtumo praktiškai nėra: papildomo rekursinio iškvietimo ir pogrupių bei kilpos ilgių palyginimo organizavimo sąnaudos yra maždaug tokios pat eilės. Tačiau jokiu būdu rekursijos gylis neviršys log 2 n, o blogiausiu išsigimusio atskyrimo atveju jis paprastai bus ne didesnis kaip 2 – visas apdorojimas vyks pirmojo rekursijos lygio cikle.
- Padalinkite masyvą ne į dvi, o į tris dalis (žr. Dual Pivot Quicksort).
Privalumai ir trūkumai
Privalumai:
Trūkumai:
Pastabos
Literatūra
- Ananija V. Levitinas Skyrius 4. Išskaidymo metodas: Greitas rūšiavimas// Algorithms: Introduction to Design and Analysis = Introduction to The Design and Analysis of Algorithms. - M.: „Williams“, 2006. - 174-179 p. - ISBN 5-8459-0987-2
- Cormen, T., Leiserson, C., Rivest, R., Stein, K. 7 skyrius. Greitas rūšiavimas// Algoritmai: konstravimas ir analizė = Introduction to Algorithms / Red. I. V. Krasikova. - 2 leidimas. - M.: Williams, 2005. - 198-219 p. - ISBN 5-8459-0857-4
svetimas 2011 m. gegužės 30 d., 15.24 val Greitas rūšiavimas ir su kuo jį valgyti
Sveiki visi! Pakalbėsiu apie greitojo rūšiavimo algoritmą ir parodysiu, kaip jį galima įgyvendinti programiškai.
Taigi greitasis rūšiavimas arba, pagal funkcijos pavadinimą C, Qsort yra rūšiavimo algoritmas, kurio sudėtingumas vidutinis yra O(n log(n)). Jo esmė itin paprasta: pasirenkamas vadinamasis atskaitos elementas, o masyvas suskirstomas į 3 pogrupius: mažesnį už atskaitą, lygų atskaitai ir didesnį už nuorodą. Tada šis algoritmas rekursyviai taikomas posistemiams.
Algoritmas
- Atraminio elemento pasirinkimas
- Masyvą padaliname į 3 dalis
- Mes sukuriame kintamuosius l ir r - atitinkamai nagrinėjamos pogrupio pradžios ir pabaigos indeksus
- Didinkite l, kol l-asis elementas bus mažesnis už atskaitos elementą
- Sumažinkite r, kol r-asis elementas bus didesnis už atskaitos elementą
- Jei l vis tiek yra mažesnis už r, pakeiskite l-tąjį ir r-ąjį elementus, padidinkite l ir sumažinkite r
- Jei l staiga tampa didesnis už r, tada ciklą nutraukiame
- Kartojame rekursyviai, kol pasieksime 1 elemento masyvą
Na, neatrodo taip sunku. Ar galime tai įgyvendinti C? Jokiu problemu!
void qsort(int b, int e)
{
int l = b, r = e;
int piv = arr[(l + r) / 2]; // Pavyzdžiui, paimkime vidurinį kaip atskaitos elementą
kol (l<= r)
{
o (arr[l]< piv)
l++;
while (arr[r] > piv)
r--;
jei (l<= r)
apsikeisti (arr, arr);
}
jei (b< r)
qsort(b,r);
jei (e > l)
qsort(l, e);
} /* ----- funkcijos qsort pabaiga ----- */// qsort (0, n-1);
* Šis šaltinio kodas buvo paryškintas naudojant šaltinio kodo žymėjimą .
Šis įgyvendinimas turi nemažai trūkumų, pvz., galimą dėklo perpildymą dėl didelio įdėtos rekursijos kiekio ir tai, kad atskaitos elementas visada laikomas viduriniu. Pavyzdžiui, tai gali būti normalu, bet sprendžiant, pavyzdžiui, olimpiados uždavinius, gudri žiuri gali specialiai atrinkti tokius testus, kad šis sprendimas jiems veiktų per ilgai ir neperžengtų ribos. Iš esmės kaip atskaitos elementą galite paimti bet kurį elementą, tačiau geriau, kad jis būtų kuo arčiau medianos, kad galėtumėte jį pasirinkti atsitiktinai arba paimti vidutinę reikšmę iš pirmos, vidutinės ir paskutinės. Našumo priklausomybė nuo atskaitos elemento yra vienas iš algoritmo trūkumų, nieko negalima padaryti, tačiau labai retai įvyksta didelis našumo pablogėjimas, dažniausiai rūšiuojant specialiai pasirinktą skaičių rinkinį. Jei vis tiek reikia rūšiavimo, kuris garantuotai veiks greitai, galite naudoti, pavyzdžiui, heapsort, kuris visada veikia griežtai O(n log n). Paprastai Qsort vis tiek pranoksta kitus, nereikalauja daug papildomos atminties ir yra gana paprasta įdiegti, todėl yra pelnytai populiarūs.
Rašiau pats, retkarčiais žvilgtelėdamas į Vikipediją. Naudodamasis proga, norėčiau išreikšti savo padėką nuostabiems PetrSU dėstytojams ir studentams, kurie išmokė mane daug naudingų dalykų, įskaitant ir šį algoritmą!
Žymos: Qsort, greitas rūšiavimas, rūšiavimo algoritmai, algoritmai, C