Tema
/
Algoritmai ir duomenų struktūros GO
Pamoka 8 / 15 Efektyvus rūšiavimas ~60 min
Teorija

Du algoritmai pseudokodu

Du algoritmai, viena idėja: skaidyk pusiau, spręsk dalis, sudėk atgal. Rekursija tau jau pažįstama iš 5 pamokos — ten ji buvo apėjimas, čia bus rikiavimas.

Skiriasi jie tuo, kur atliekamas darbas: suliejimo rikiavime — sudedant atgal, greitajame — skaidant.

Suliejimo rikiavimas

MergeSort(items):
    jei len(items) <= 1: grąžink kopiją
    mid ← len(items) / 2
    left  ← MergeSort(items[:mid])
    right ← MergeSort(items[mid:])
    grąžink Merge(left, right)

Merge(a, b):
    out ← tuščias, talpa len(a)+len(b)
    i ← 0; j ← 0
    kol i < len(a) ir j < len(b):
        cmp.Hit()
        jei a[i].Title <= b[j].Title:
            out ← out + a[i];  i ← i + 1
        kitaip:
            out ← out + b[j];  j ← j + 1
        moves.Hit()
    pridėk likusius iš a, tada iš b (kiekvienas moves.Hit())
    grąžink out

Skaidymas nieko nelygina. Visas darbas yra Merge, ir jis tiesinis: kiekvienas elementas paliečiamas vieną kartą. Gylių yra log₂ n, kiekviename gyliuje darbo n — iš to ir gaunasi O(n log n).

Vienas simbolis, kuriame gyvena stabilumas

jei a[i].Title <= b[j].Title

Tas <= reiškia: lygiavertėje situacijoje laimi KAIRĖ pusė. Kairė pusė yra ta, kuri masyve buvo anksčiau — taigi lygūs elementai išlaiko pradinę tvarką.

Parašyk < vietoj <=, ir rikiavimas vis tiek veiks. Testai, tikrinantys tik tvarką, praeis. Bet stabilumas dings — o kur tai svarbu, pamatysi 5 žingsnyje.

Greitasis rikiavimas

QuickSort(items):
    jei len(items) <= 1: grįžk
    p ← Partition(items, pivotIndex)
    QuickSort(items[:p])
    QuickSort(items[p+1:])

Partition(items, pivotIdx):
    perkelk items[pivotIdx] į priekį (moves.Hit(), jei judėjo)
    pivot ← items[0].Title
    i ← 1
    kiekvienam j nuo 1 iki len(items)-1:
        cmp.Hit()
        jei items[j].Title < pivot:
            sukeisk items[i] ir items[j];  moves.Hit();  i ← i + 1
    sukeisk items[0] ir items[i-1];  moves.Hit()
    grąžink i-1

Čia atvirkščiai: visas darbas yra skaidyme, o sudėti atgal nieko nereikia — kai abi pusės surikiuotos, masyvas jau surikiuotas.

Ir dirba jis vietoje: jokio antro masyvo, priešingai nei suliejimo rikiavimas.

Bet pivotas yra spėjimas

Partition padalija masyvą ties pivotu. Jei pivotas — mediana, gauni dvi lygias puses ir log₂ n gylį.

Jei pivotas — mažiausias elementas, kairė pusė tuščia, o dešinė turi n−1 elementą. Ir taip kiekviename žingsnyje.

Kada pivotas nuolat būna mažiausias? Kai imi pirmą elementą, o masyvas jau surikiuotas.

Spėk prieš skaitydamas toliau

Septintoje pamokoje -order sorted buvo įterpimo rikiavimo geriausias atvejis: 9 999 palyginimai vietoj 25 milijonų.

Ką ta pati vėliavėlė padarys greitajam rikiavimui su pirmo elemento pivotu?

Užsirašyk spėjimą. Dauguma mano, kad surikiuoti duomenys — lengvesnis darbas.