2.1 Sammenligningsbaserte sorteringer
`Insertion-Sort`, `Merge-Sort`, `Quicksort` og `Randomized-Quicksort` — mekanikk, kjøretider (beste/verste/forventet) og `Θ(n\lg n)`-nedre grensen.
er de 17 settene fra august 2015 til august 2023 som er gjennomgått tema for
tema — det er nevneren hver gang boka oppgir en prosent. Ingen andre temaer
slår det, og bare to andre er like høye (asymptotisk notasjon og
NP/reduksjoner).
Temaet kommer i to sjangre, og de skrives ut i klarspråk her:
- Sjanger E — kjøretidskunnskap, altså at du oppgir kjøretiden til en
navngitt algoritme i det strammeste uttrykket som er riktig. Spørsmålet er
ofte spisset: «beste tilfelle», «verste tilfelle», «forventet» — og de tre
har ulike svar for tre av de fire algoritmene i dette kapitlet.
- Sjanger C — håndkjøring, altså at du utfører algoritmen steg for steg på
papir og oppgir bare sluttilstanden. Selve håndkjøringsdrillen ligger i
kap. 2.4; her møter du mekanikken første gang.
Høyeste prioritet — dette må sitte. Eksamen er hjelpemiddelfri, så
kjøretidstabellen nederst i kapitlet er rent puggestoff.
To ting er verdt å merke seg med én gang:
1. Skillet mellom garantert og inputavhengig kjøretid er selve poenget.
Merge-Sort er uansett hva du gir den. Quicksort er
forventet og i verste tilfelle. Å svare
«» på et spørsmål om Quicksorts verste tilfelle er galt,
selv om tallet stemmer for det vanlige tilfellet.
2. Den nedre grensen gjelder bare sortering som
sammenligner elementer med hverandre. Kap. 2.2
viser sorteringer som går i lineær tid nettopp fordi de ikke sammenligner.
Slik er kapitlet lagt opp (55 min):
| Innhold | Tid |
|---|---|
Insertion-Sort og løkkeinvarianten | ca. 12 min |
Merge-Sort og rekurrensen bak den | ca. 14 min |
Quicksort og pivotens rolle | ca. 13 min |
Randomized-Quicksort | ca. 6 min |
| Den nedre grensen for sammenligningssortering | ca. 10 min |
Forkunnskaper
- kap. 1.1 — de asymptotiske symbolene. Du trenger
skillet mellom (bare øvre grense er vist), (bare nedre) og
(tett grense begge veier), fordi dette kapitlet bruker alle tre
bevisst. I hele boka betyr det samme som .
- kap. 1.2 — forenkling. Kjøretidssvar oppgis alltid i
det strammeste uttrykket som er riktig.
- kap. 1.4 — masterteoremet. Merge-Sorts kjøretid
utledes her ved å løse rekurrensen , og det gjør
vi med masterteoremet.
Vil du se sortering konkret i kode først, er
Sortering: boblesortering, .sort() og gitt sort_list
et mykere første møte. Du trenger ikke mer enn å kunne følge en løkke med
blyant.
Insertion-Sort og løkkeinvarianten (~12 min)
Du har fjorten pasientjournaler i en bunke og skal legge dem i stigende
rekkefølge etter registreringsnummer. Den naturlige framgangsmåten er å ta én
journal av gangen, holde den i hånden, og skyve den inn på riktig plass i den
delen av bunken du allerede har ordnet. Det er nøyaktig Insertion-Sort.
Algoritmen er interessant på eksamen av to grunner. Den er den ene sorteringen
som er raskere på pen input — allerede sortert input gir lineær tid — og
den er den letteste å begrunne, fordi begrunnelsen er en løkkeinvariant:
en påstand om tilstanden som er sann før løkka begynner, forblir sann gjennom
hver runde, og gir det du vil ha når løkka er ferdig.
En løkkeinvariant er en påstand om tilstanden som gjelder rett før hver
runde i en løkke.
Den brukes til å vise at en algoritme er riktig, og har alltid tre ledd:
initialisering (påstanden er sann før første runde), vedlikehold (er
den sann før en runde, er den sann før den neste), og terminering (når
løkka stopper, gir påstanden nettopp det resultatet vi ville ha).
Ordet «invariant» betyr her det som ikke endrer seg — ikke tilstanden selv,
men påstanden om den.
A[1..n], indeks fra 1.Elementene kan sammenlignes med
< og >; ingenting annet antas om dem.Sorteringen skjer på stedet (in-place): utenom noen få hjelpevariabler
brukes ingen ekstra plass som vokser med .
Prebetingelse: A[1..n] inneholder elementer i vilkårlig rekkefølge.
Postbetingelse: A[1..n] inneholder de samme elementene i stigende
rekkefølge.
Insertion-Sort(A)
Input: array A[1..n]
Output: A sortert stigende, paa stedet
for j = 2 to A.length
key = A[j]
i = j - 1
while i >= 1 and A[i] > key
A[i+1] = A[i]
i = i - 1
A[i+1] = key
Kjoeretid: Theta(n) beste, Theta(n^2) versteInvarianten i én setning: rett før hver runde med indeks j erA[1..j-1] sortert og inneholder nøyaktig de elementene som lå der fra start.
Kjøretid: den ytre løkka går ganger. Den indre while-løkka gjør
ingen runder når A[j] allerede er større enn alt til venstre — da blir
totalen . Er arrayet sortert synkende, må hvert element skyves
helt fram til indeks 1, og totalen blir ,
altså .
Seks måleverdier fra en værstasjon ligger i den rekkefølgen de ble avlest:A = 34, 12, 47, 8, 23, 19 (indeks fra 1).
Kjør Insertion-Sort(A) og oppgi arrayet etter hver runde i den ytre løkka.
Tell til slutt hvor mange enkeltskyv den indre løkka gjorde til sammen.
Løkka starter på , fordi A[1..1] er sortert allerede.
Runde j | key | Antall skyv i while-løkka | Array etter runden |
|---|---|---|---|
| 2 | 12 | 1 | 12, 34, 47, 8, 23, 19 |
| 3 | 47 | 0 | 12, 34, 47, 8, 23, 19 |
| 4 | 8 | 3 | 8, 12, 34, 47, 23, 19 |
| 5 | 23 | 2 | 8, 12, 23, 34, 47, 19 |
| 6 | 19 | 3 | 8, 12, 19, 23, 34, 47 |
Til sammen 9 skyv i den indre løkka.
Sluttilstanden — det du ville levert på eksamen:
8, 12, 19, 23, 34, 47Legg merke til runde 3:
key = 47 er større enn alt til venstre, så while-løkkagjør null runder. Det er nettopp det som skjer i hver runde når inputen
allerede er sortert, og det er derfor beste tilfelle er .
På eksamen leverer du bare sluttarrayet — tavlen er her for å vise hvordan du
kommer dit.
(Innstegsoppgave, sjanger D — definisjon med egne ord, altså én presis setning
med hovedpoenget først.)
Hva er beste tilfelle for Insertion-Sort, hvilken input gir det, og hva er
verste tilfelle?
Kjør Insertion-Sort på A = 5, 3, 9, 1 og oppgi arrayet etter hver runde i
den ytre løkka.
Merge-Sort og rekurrensen bak den (~14 min)
Insertion-Sort bruker kvadratisk tid på store arrayer, og det er for dyrt.
Den andre ideen er splitt og hersk: del arrayet i to like store halvdeler,
sorter hver halvdel for seg, og flett de to sorterte halvdelene sammen. Selve
arbeidet ligger i flettingen.
Flettingen er lettere enn den ser ut. Har du to sorterte bunker foran deg, er
det minste elementet i unionen alltid det øverste i én av de to bunkene. Du
sammenligner de to toppene, tar den minste, og gjentar.
A[1..n], indeks fra 1.Indeksene tilfredsstiller
p <= q < r. Rutinen bruker to hjelpearrayer L ogR, og er derfor ikke på stedet.Prebetingelse: A[p..q] er sortert, og A[q+1..r] er sortert.
Postbetingelse: A[p..r] er sortert og inneholder de samme elementene.
Merge(A, p, q, r)
Input: A[p..q] og A[q+1..r] er hver for seg sorterte
Output: A[p..r] sortert
kopier A[p..q] til L og A[q+1..r] til R
legg en vaktpost stoerre enn alle elementer bakerst i L og i R
i = 1
j = 1
for k = p to r
if L[i] <= R[j]
A[k] = L[i]
i = i + 1
else
A[k] = R[j]
j = j + 1
Kjoeretid: Theta(r - p + 1)Invarianten i én setning: rett før hver runde med indeks k inneholderA[p..k-1] de minste elementene fra L og R, i sortert rekkefølge,
og L[i] og R[j] er de minste elementene som ennå ikke er kopiert tilbake.
Merk <= og ikke < i testen. Ved likhet plukkes elementet fra
venstre bunke først. Det er den lille detaljen som gjør Merge-Sort
stabil: like elementer beholder sin innbyrdes rekkefølge, fordi venstre
bunke lå først i arrayet.
Kjøretid: hver runde i for-løkka plasserer nøyaktig ett element, og det er
elementer å plassere — altså , lineært i lengden på
delen som flettes.
To sorterte halvdeler skal flettes: venstre er 2, 5, 9, høyre er3, 4, 11.
Utfør Merge og oppgi hvilken sammenligning som gjøres i hvert steg, og hvor
mange sammenligninger flettingen koster til sammen.
| Steg | Sammenligning | Plukket | A etter steget |
|---|---|---|---|
| 1 | 2 mot 3 | 2 (venstre) | 2 |
| 2 | 5 mot 3 | 3 (høyre) | 2, 3 |
| 3 | 5 mot 4 | 4 (høyre) | 2, 3, 4 |
| 4 | 5 mot 11 | 5 (venstre) | 2, 3, 4, 5 |
| 5 | 9 mot 11 | 9 (venstre) | 2, 3, 4, 5, 9 |
| 6 | venstre bunke tom | 11 (høyre) | 2, 3, 4, 5, 9, 11 |
Sluttilstanden:
2, 3, 4, 5, 9, 11.Seks elementer ut, men bare fem sammenligninger: det siste steget trenger
ingen, fordi den ene bunken er tom og resten kan kopieres rett over. Generelt
koster fletting av elementer høyst sammenligninger og nøyaktig
plasseringer — begge deler .
Legg merke til at ingen sammenligning noen gang involverer to elementer fra
samme bunke. De er allerede innbyrdes sortert, og den informasjonen kastes
ikke bort. Det er hele gevinsten ved splitt og hersk.
A[1..n], indeks fra 1. Kalletutenfra er
Merge-Sort(A, 1, A.length). Rutinen krever hjelpeplass påceller til flettingen, og går derfor ikke på stedet.
Prebetingelse: p <= r, og A[p..r] inneholder elementene som skal
sorteres.
Postbetingelse: A[p..r] er sortert stigende.
Merge-Sort(A, p, r)
Input: array A[p..r]
Output: A[p..r] sortert stigende
if p < r
q = floor((p + r) / 2)
Merge-Sort(A, p, q)
Merge-Sort(A, q+1, r)
Merge(A, p, q, r)
Kjoeretid: Theta(n lg n)Grunnideen i én setning: en del med ett element er sortert per definisjon,
og to sorterte deler kan flettes til én sortert del i lineær tid — altså
holder det å halvere seg ned til enkeltelementer og flette seg opp igjen.
Kjøretid: delingen koster konstant tid, de to rekursive kallene er hver på
halvparten så stor input, og flettingen koster . Det gir
Her er og , så . Siden
, treffer vi tilfelle 2
i masterteoremet med , og svaret blir . Ingen input gjør den raskere, og ingen gjør den tregere:
grensen er tett begge veier.
Det er lett å tro at logaritmefaktoren i tilfelle 2 må være der fra før for at
tilfellet skal gjelde. Det må den ikke.
Pensumvarianten av tilfelle 2 er med
— ikke-negativ, altså. Merge-Sort har , og faller midt
inne i tilfellet. Svaret får da nøyaktig én logaritmefaktor: .
Det dokumenterte unntaket går den andre veien: en rekurrens som svarer til
negativ , for eksempel , faller utenfor
pensumvarianten. Se kap. 1.4.
En sorteringsrutine deler arrayet i tre like store deler, sorterer hver av
dem rekursivt, og fletter de tre sorterte delene i lineær tid.
a) Sett opp rekurrensen.
b) Løs den, og navngi metoden.
Ta stilling til hver av påstandene:
a) Merge-Sort sorterer på stedet.
b) Merge-Sort er stabil.
c) Merge-Sort er raskere på et allerede sortert array enn på et
tilfeldig array.
Quicksort og pivotens rolle (~13 min)
Merge-Sort deler alltid midt på, og betaler for det med hjelpeplass.Quicksort snur det: den deler etter verdi i stedet for etter posisjon, og
slipper dermed flettingen helt. Prisen er at delingen kan bli skjev.
Delingen gjøres av Partition. Den velger et element som pivot — et
skilleelement — og stokker om delen slik at alt som er mindre enn eller lik
pivoten havner til venstre for den, og alt som er større havner til høyre.
Etterpå står pivoten på sin endelige plass, og de to sidene kan sorteres
uavhengig. Mekanikken i Partition tas i detalj i
kap. 2.3; her trenger du kontrakten.
Et pivot er skilleelementet en partisjonering deler om.
Etter Partition(A, p, r) står pivoten på en indeks q slik at alt iA[p..q-1] er mindre enn eller lik pivoten, og alt i A[q+1..r] er større.
Pivoten selv er da ferdig plassert og røres aldri igjen.
I denne boka velger Partition siste element i delen som pivot, slik CLRS
gjør. Randomized-Partition bytter først et tilfeldig element inn på siste
plass, og kaller så Partition.
A[1..n], indeks fra 1. Kalletutenfra er
Quicksort(A, 1, A.length). Partition(A, p, r) bruker sisteelement
A[r] som pivot og returnerer pivotens sluttindeks q. Sorteringengår på stedet.
Prebetingelse: A[p..r] inneholder elementene som skal sorteres.
Postbetingelse: A[p..r] er sortert stigende.
Quicksort(A, p, r)
Input: array A[p..r]
Output: A[p..r] sortert stigende, paa stedet
if p < r
q = Partition(A, p, r)
Quicksort(A, p, q-1)
Quicksort(A, q+1, r)
Kjoeretid: Theta(n lg n) forventet, Theta(n^2) versteGrunnideen i én setning: når pivoten står på sin endelige plass, er
problemet redusert til to uavhengige, mindre sorteringsproblemer — og ingen
fletting trengs etterpå, fordi rekkefølgen mellom de to sidene allerede er
riktig.
Kjøretid: partisjoneringen av en del med elementer koster
. Blir delingen jevn, får vi . Blir den maksimalt skjev — pivoten er alltid det største
eller minste elementet — får vi , som gir
. Det verste tilfellet inntreffer nettopp på et allerede
sortert array når pivoten er siste element.
Sju ordrenumre ligger i mottaksrekkefølge: A = 26, 9, 41, 17, 33, 12, 22
(indeks fra 1).
Kjør Quicksort(A, 1, 7) med siste element som pivot. Oppgi arrayet etter
hver partisjonering, og hvor dypt rekursjonen går.
Bare kall som faktisk partisjonerer er tatt med; kall på deler med null eller
ett element gjør ingenting.
| Kall | Del | Pivot | q | Array etter partisjoneringen |
|---|---|---|---|---|
Quicksort(A, 1, 7) | A[1..7] | 22 | 4 | 9, 17, 12, 22, 33, 41, 26 |
Quicksort(A, 1, 3) | A[1..3] | 12 | 2 | 9, 12, 17, 22, 33, 41, 26 |
Quicksort(A, 5, 7) | A[5..7] | 26 | 5 | 9, 12, 17, 22, 26, 41, 33 |
Quicksort(A, 6, 7) | A[6..7] | 33 | 6 | 9, 12, 17, 22, 26, 33, 41 |
Sluttilstanden:
9, 12, 17, 22, 26, 33, 41.Dybden er 3: kallet på hele arrayet, deretter på
A[5..7], deretter påA[6..7]. Fire partisjoneringer til sammen på sju elementer.Legg merke til den første delingen. Pivoten 22 havnet på indeks 4, altså
nesten midt på — det er den heldige varianten. Hadde arrayet vært
9, 12, 17, 22, 26, 33, 41 fra start, ville hver pivot vært det største
elementet i sin del, hver deling ville skilt av nøyaktig ett element, og
dybden ville blitt 6 i stedet for 3.
Quicksort med siste element sompivot, og på hvilken input oppstår den?
b) Hva er kjøretiden i det vanlige tilfellet, og hvilket symbol hører til
det svaret?
Randomized-Quicksort (~6 min)
Problemet med Quicksort er ikke at det finnes en dårlig input — det er at
den dårlige inputen er vanlig. Sorterte og nesten sorterte data dukker opp
overalt.
Løsningen er å flytte tilfeldigheten fra inputen til algoritmen. I stedet for
alltid å ta siste element som pivot, trekker Randomized-Partition et
tilfeldig element i delen, bytter det til siste plass, og partisjonerer som
før.
Quicksort: A[1..n], indeks fra 1, påstedet.
Random(p, r) returnerer et tilfeldig heltall i [p, r], hvert likesannsynlig.
Prebetingelse: A[p..r] inneholder elementene som skal sorteres.
Postbetingelse: A[p..r] er sortert stigende. Resultatet er alltid
riktig; det er bare kjøretiden som avhenger av de tilfeldige trekkene.
Randomized-Partition(A, p, r)
Input: array A[p..r]
Output: pivotens sluttindeks q
i = Random(p, r)
bytt A[i] og A[r]
return Partition(A, p, r)
Randomized-Quicksort(A, p, r)
if p < r
q = Randomized-Partition(A, p, r)
Randomized-Quicksort(A, p, q-1)
Randomized-Quicksort(A, q+1, r)
Kjoeretid: Theta(n lg n) forventet, uansett inputGrunnideen i én setning: når pivoten trekkes tilfeldig, er sannsynligheten
for en rimelig jevn deling stor i hvert kall, og forventningen over alle
trekkene blir — uten at noen bestemt input kan framtvinge det
dårlige tilfellet.
Kjøretid: forventet, for enhver input. Verste
tilfelle er fortsatt — trekker du uheldig hver eneste gang, går
det like galt — men nå er «uheldig» et spørsmål om terningkast, ikke om hvem
som leverte dataene.
De to første koster hele oppgaven.
- Å oppgi feil kjøretidsfakta. Dette er felle #9 — å bomme på et tall
som skal kunnes utenat. De to hyppigste er å påstå at Insertion-Sort har
i beste tilfelle (den er ), og å oppgi
Quicksorts forventede kjøretid som svar på et spørsmål om verste tilfelle.
Kontrollen: les spørsmålet én gang til og finn ordet «beste», «verste» eller
«forventet».
- Å blande garantert og inputavhengig. Merge-Sort er
uansett; Quicksort er forventet. Ordet «forventet» er
ikke en høflighetsfrase — det er forskjellen mellom en garanti og et
gjennomsnitt.
- Å tro at Merge-Sort går på stedet. Flettingen krever hjelpearrayer på
celler. Quicksort, Heapsort og Insertion-Sort går på
stedet; Merge-Sort gjør det ikke.
- Å bruke -grensen på alt. Grensen gjelder bare
sorteringer som avgjør rekkefølgen ved å sammenligne elementer med
hverandre. Kap. 2.2 viser sorteringer som går i
lineær tid fordi de bruker nøkkelverdiene direkte.
- Å påstå at Randomized-Quicksort er garantert . Verste
tilfelle er fortsatt . Det som er nytt, er at ingen input kan
framtvinge det.
Og den gjennomgående: å oppgi der bare er vist. Har du bare
begrunnet en øvre grense, skriv .
Den nedre grensen for sammenligningssortering (~10 min)
Alle fire algoritmene over har det til felles at de bare stiller ett slags
spørsmål om dataene: «er dette elementet mindre enn hint?» De kan flytte
elementer rundt, men de kan aldri se på verdien og regne ut hvor den hører
hjemme. Slike algoritmer kalles sammenligningsbaserte.
Det setter en grense som ingen smartere idé kan komme under, og grensen er
verdt å kunne argumentere for på tre linjer.
En sortering er sammenligningsbasert når den bare bruker sammenligninger
mellom elementpar — «er ?» — til å avgjøre rekkefølgen.
Insertion-Sort, Merge-Sort, Quicksort og Heapsort er alle
sammenligningsbaserte. De vet ingenting om hva elementene er, bare hvordan
de forholder seg til hverandre.
Sorteringene i kap. 2.2 er ikke sammenligningsbaserte:
de bruker nøkkelverdien som en indeks, og er derfor ikke bundet av grensen
under.
sammenligninger i verste tilfelle.
Argumentet, kort. Kjøringen kan tegnes som et beslutningstre: hver
indre node er én sammenligning, og de to grenene er de to svarene. Hver
løvnode er én mulig utgangsrekkefølge av elementene.
Med forskjellige elementer finnes mulige rekkefølger, og algoritmen
må kunne ende opp i hver av dem — ellers finnes en input den sorterer feil.
Altså har treet minst løvnoder.
Et binært tre med høyde har høyst løvnoder. Da må ,
altså . Og : minst halvparten av
faktorene i er større enn , så , som gir
.
Høyden er antall sammenligninger i verste tilfelle, altså er den
.
Hva grensen ikke sier. Den sier ingenting om sorteringer som ikke
sammenligner, og den sier ingenting om beste tilfelle for en enkelt
algoritme. Merge-Sort og Heapsort når grensen, og er dermed
asymptotisk optimale blant sammenligningssorteringene.
En kandidat skriver i besvarelsen sin: «Siden enhver sortering bruker minst
tid, kan ingen sortering være lineær.»
Er utsagnet riktig? Svar ja eller nei, og forklar kort.
Fyll ut tabellen for de fire algoritmene i dette kapitlet.
| Algoritme | Beste | Verste | På stedet? | Stabil? |
|---|---|---|---|---|
Insertion-Sort | ||||
Merge-Sort | ||||
Quicksort | ||||
Randomized-Quicksort |
En kollega foreslår å forbedre Quicksort slik: «Før vi partisjonerer,
sjekker vi om delen allerede er sortert. Er den det, hopper vi over hele
rekursjonen. Da blir verste tilfelle .»
Stemmer konklusjonen? Svar ja eller nei, og begrunn.
Et laboratorium har prøverør med hver sin måleverdi. Du skal finne ut om
to av rørene har nøyaktig samme verdi, og i så fall hvilke to.
Beskriv en algoritme som bruker tid, og forklar hvorfor
kjøretiden holder.
Kjøretidene samlet
Dette er kapitlets puggeflate. Eksamen er hjelpemiddelfri, så tabellen må ligge
i hodet.
| Algoritme | Beste | Verste | Forventet | Krav / egenskap |
|---|---|---|---|---|
Insertion-Sort | på stedet, stabil; beste tilfelle er ferdigsortert input | |||
Merge-Sort | ikke på stedet ( hjelpeplass), stabil | |||
Quicksort | på stedet, ustabil; verste tilfelle på sortert input | |||
Randomized-Quicksort | for enhver input | på stedet, ustabil | ||
Merge (ett flettesteg) | = antall elementer som flettes; krever to sorterte deler | |||
Partition (ett steg) | ett gjennomløp, på stedet |
Heapsort hører også hjemme i denne oversikten: den er garantert, går på stedet og er ustabil. Haugstrukturen den bygger på, tas i
kap. 3.1.
Én presisering som er verdt å ta med seg. Ingen av de fire kan komme under
i verste tilfelle, og
Merge-Sort når grensen. Det betyrikke at
Merge-Sort alltid er det beste valget i praksis — Quicksort harmindre konstanter og trenger ikke hjelpeplass — men på eksamen er det den
asymptotiske garantien som teller.
Begrepsbank
Begrepsbanken er flashcard- og repetisjonsstoff — den gjentar det du nettopp
har lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet
gjelder kjernestoffet.
sorterer A[1..n] ved å ta ett element av gangen og skyve det bakover til sin
plass i den allerede sorterte delen til venstre.
Kjøretid beste (ferdigsortert input), verste
(synkende sortert input).
Går på stedet og er stabil. Den eneste av de fire i dette kapitlet som
faktisk blir raskere når inputen er pen.
fletter to sorterte deler A[p..q] og A[q+1..r] til én sortert del ved å
plukke det minste av de to fremste elementene om gangen.
Kjøretid , altså lineært i antallet elementer som flettes.
Krever at begge delene allerede er sortert. Ved likhet plukkes fra venstre
del — det er det som gjør Merge-Sort stabil.
sorterer ved splitt og hersk: del i to like halvdeler, sorter hver rekursivt,
flett resultatene.
Kjøretid i alle tilfeller — ingen input gjør den raskere eller
tregere.
Ikke på stedet: flettingen krever hjelpeplass. Til gjengjeld er
den stabil, og garantien er tett.
stokker A[p..r] om pivoten slik at alt mindre enn eller lik pivoten står til
venstre for den og alt større til høyre, og returnerer pivotens sluttindeksq.
Kjøretid — ett gjennomløp, på stedet.
Pivoten er ferdig plassert etterpå og røres aldri igjen. I denne boka er
pivoten siste element i delen.
partisjonerer A[p..r] om et pivot og sorterer de to sidene rekursivt. Ingen
fletting trengs, fordi rekkefølgen mellom sidene allerede er riktig.
Kjøretid forventet, verste.
Går på stedet, men er ustabil. Verste tilfelle inntreffer på allerede
sortert input når pivoten er siste element.
samme algoritme, men pivoten trekkes tilfeldig i hvert kall før
partisjoneringen.
Kjøretid forventet for enhver input; verste tilfelle er
fortsatt .
Forskjellen er hvem som bestemmer. Ingen input kan lenger framtvinge det
dårlige tilfellet — det avhenger bare av terningkastene.
en påstand om tilstanden som gjelder rett før hver runde i en løkke, og som
brukes til å vise at algoritmen er riktig.
Har tre ledd: initialisering, vedlikehold og terminering.
For Insertion-Sort: rett før runde j er A[1..j-1] sortert og
inneholder de samme elementene som fra start.
en algoritme går på stedet når den bare bruker et konstant antall
hjelpevariabler utenom selve inputen — altså ekstra plass.
Insertion-Sort, Quicksort og Heapsort går på stedet; Merge-Sort gjør
det ikke.
Rekursjonsstakken telles vanligvis ikke med i denne bokas bruk av
begrepet.
en sortering er stabil når to elementer med lik nøkkel beholder sin
innbyrdes rekkefølge fra input til output.
Insertion-Sort og Merge-Sort er stabile; Quicksort og Heapsort er det
ikke.
Egenskapen er avgjørende når du sorterer etter én nøkkel om gangen, slikRadix-Sort gjør. Se kap. 2.2.
designteknikken der problemet deles i mindre deler av samme type, delene
løses rekursivt, og delløsningene settes sammen.
Kjøretiden blir en rekurrens på formen , som løses med
masterteoremet.
Delproblemene overlapper ikke — det er det som skiller teknikken fra
dynamisk programmering.
en modell av en sammenligningsbasert sortering der hver indre node er én
sammenligning og hver løvnode er én mulig utgangsrekkefølge.
Treet må ha minst løvnoder, og et binært tre med så mange løv har høyde
minst .
Høyden er antall sammenligninger i verste tilfelle — derav den nedre
grensen.
ingen sammenligningsbasert sortering kan bruke færre enn
sammenligninger i verste tilfelle.
Følger av beslutningstre-argumentet.
Gjelder bare sammenligningsbaserte sorteringer, og bare verste tilfelle.Merge-Sort og Heapsort når grensen og er dermed asymptotisk optimale i den
klassen.
en sortering som bare bruker sammenligninger mellom elementpar til å avgjøre
rekkefølgen, og som aldri regner på selve nøkkelverdien.
De fire algoritmene i dette kapitlet er alle sammenligningsbaserte, og det erHeapsort også.
Konsekvensen er i verste tilfelle. Sorteringer som bruker
nøkkelen som indeks, faller utenfor.
skilleelementet en partisjonering deler om.
Etter partisjoneringen står pivoten på sin endelige plass, med alt mindre eller
likt til venstre og alt større til høyre.
Pivotvalget avgjør kjøretiden. Siste element som pivot gir på
sortert input; tilfeldig valgt pivot gir forventet uansett.
den lengste kjøretiden over alle inputer av størrelse .
Oppgis med når grensen er tett, og med når bare en øvre grense er
vist.
Dette er standardsvaret når en oppgave sier «kjøretid» uten å presisere
noe.
gjennomsnittet av kjøretiden over de tilfeldige valgene algoritmen selv gjør,
eller over en antatt fordeling av inputene.
Randomized-Quicksort er forventet for enhver input.
Forventet er ikke garantert. Ordet må stå i svaret; utelates det, har du
lovet noe algoritmen ikke holder.
den korteste kjøretiden over alle inputer av størrelse .
Bare Insertion-Sort har et beste tilfelle som er asymptotisk bedre enn
verste: mot .
Felle #9 bor her: å oppgi som beste tilfelle forInsertion-Sort. Riktig svar er .
Merge-Sort-rekurrensen: to halvdeler, hver av størrelse , pluss lineærtarbeid til flettingen.
Løses med masterteoremets tilfelle 2 () og gir .
Den samme rekurrensen beskriver Quicksort når delingen er jevn.
Quicksorts verste tilfelle: hver partisjonering skiller av nøyaktig ettelement.
Løses med iterasjon og gir , siden .
Masterteoremet gjelder ikke her — rekurrensen er ikke på formen
.
et hjelpeelement større enn alle virkelige elementer, lagt bakerst i begge
hjelpearrayene.
Det gjør at flettingen slipper å teste om en av bunkene er tom i hver runde —
bunken med vaktposten taper alltid sammenligningen.
Ren forenkling av koden. Kjøretiden blir den samme uten den.
oppgavetypen der du oppgir kjøretiden til en navngitt algoritme.
Svarformen er ett uttrykk, i det strammeste som er riktig, med der
grensen er tett og der bare øvre grense er vist.
Les alltid om spørsmålet gjelder beste, verste eller forventet. Det er der
poengene faller.
oppgavetypen der du utfører en navngitt algoritme steg for steg på papir og
oppgir sluttilstanden.
Svarformen er kun sluttilstanden, i det formatet oppgaven ber om.
Ingen ekstra uttelling for å forklare algoritmen. Drillen ligger i
kap. 2.4.
oppgavetypen der du får en påstand og skal ta stilling til den.
Svarformen er ja eller nei først, deretter én presis setning som
begrunner.
Et motbevis er en fullgod begrunnelse når svaret er nei — én konkret input
der påstanden svikter, holder.
Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.
Skolesaga er en uavhengig læringsressurs og er ikke tilknyttet eller godkjent av Norges teknisk-naturvitenskapelige universitet. Dette er ikke offisielt studiemateriell. Les mer.