1.1 Asymptotisk notasjon — O (og kort Ω, Θ)
O-notasjonen (øvre grense) som IN2010s arbeidshest, med kort omtale av Ω og Θ — grunnlaget alle kjøretidssvar hviler på.
Dette kapitlet er språket resten av boka snakker. To oppgavetyper hviler direkte
på det, og begge har dukket opp i alle sju settene (100 %):
- Sjanger B — kjøretid fra kode, altså at du får en kodesnutt og skal svare
med ett -uttrykk. Selve tellingen lærer du i
kap. 1.2; her lærer du hva svaret betyr.
- Sjanger C — kjøretids- og teorifakta, altså sant/usant-punkter om hvor
raskt noe går. Disse ligger på Del 1 av settet, som rettes automatisk og er
skalert mot gjetting.
Dette har derfor høyeste prioritet i hele boka: det må sitte, ikke fordi
kapitlet er verdt mange poeng i seg selv, men fordi hvert eneste kjøretidssvar
resten av eksamen bygger på det.
To avgrensninger sparer deg for arbeid. IN2010 bruker nesten utelukkende
; og nevnes kort her og går knapt igjen i oppgavene, og
lillebrødrene og brukes overhodet ikke. Og kjøretid forenkles i
dette faget ved å telle løkker — ikke ved å sette opp rekurrensligninger,
som ikke er IN2010-pensum.
Forkunnskaper
Dette kapitlet kan leses uten forkunnskaper fra resten av boka — det er
startpunktet.
Har du aldri møtt -notasjon før, kan disse to gi et mykere første møte:
- Algoritmedefinisjon, pseudokode og kompleksitet (Big-O)
— samme idé, forklart uten eksamenspress.
- Potenser og logaritmer — hvis føles ukjent. Du
trenger bare én ting derfra: at er svaret på spørsmålet «hvor mange
ganger kan jeg halvere før jeg er nede i 1?».
Hvorfor vi ikke måler i sekunder
Folkeregisteret i en mellomstor kommune har rundt 40 000 innbyggere. Du skal
skrive en funksjon som finner ut om en bestemt person står i registeret.
Du kan gjøre det på to måter. Du kan gå gjennom listen fra start og sammenligne
hver eneste rad — da må du i verste fall innom alle 40 000. Eller du kan, hvis
listen er sortert, slå opp på midten, se om du havnet for høyt eller for lavt,
og halvere søkeområdet: 40 000, 20 000, 10 000, og så videre. Det tar 16 steg.
Forskjellen er ikke at det ene programmet er «raskere skrevet». Forskjellen er
hvordan de to skalerer. Doble registeret til 80 000, og den første metoden
bruker dobbelt så lang tid, mens den andre bruker ett steg til. Ett eneste.
Det er dette -notasjonen fanger. Den måler ikke sekunder, for sekunder
avhenger av maskinen, programmeringsspråket og hvor travelt det er på
serveren. Den måler hvordan arbeidsmengden vokser når inputen vokser — og
det er en egenskap ved algoritmen selv, ikke ved maskinen den kjøres på.
Å si at noe er asymptotisk betyr nettopp «når blir stor». Det er en
uttalelse om oppførsel i det lange løp, ikke om et bestemt regnestykke.
Tallet som beskriver hvor stor inputen er: antall elementer i et array, antall
noder i en graf, antall tegn i en tekst. Alt annet i kjøretidsanalysen måles
mot dette tallet.
På eksamen trekkes det eksplisitt for å bruke uten å si hva det teller.
Skriv derfor alltid én setning som «her er antall bøker i registeret».
Hvordan arbeidsmengden til en algoritme vokser når blir stor, uavhengig av
maskin, språk og faste kostnader. Måles i grunnsteg, ikke i sekunder.
Praktisk konsekvens: konstanter og lavere ordensledd faller bort, fordi de ikke
påvirker hvordan uttrykket vokser.
slik at
Med ord: fra et visst punkt og oppover ligger under , bortsett fra en
fast faktor. er altså et løfte om at det ikke blir verre enn dette.
Dette er notasjonen IN2010 bruker nesten overalt, og den du skal svare med når
en oppgave ber om kjøretiden.
De to bokstavene og er hele hemmeligheten bak at virker så
grovkornet. lar deg se bort fra faste faktorer: en algoritme som bruker
steg og en som bruker steg er begge , fordi du bare velger
. Og lar deg se bort fra hva som skjer for små input: at en
kompleks algoritme er treg på tre elementer, betyr ingenting.
Dette er både styrken og svakheten. Styrken er at sier noe robust som
gjelder på enhver maskin. Svakheten er at ikke sier noe som helst om
hvilken av to algoritmer som er raskest på nettopp dine data.
En algoritme bruker grunnsteg. Vis at ved å
oppgi en konstant og en terskel som oppfyller definisjonen.
Vi skal finne og slik at for alle
.
Prøv . Da må vi ha , altså . Det stemmer for
alle .
Svar: med og er for alle ,
og dermed er .
Kontroller gjerne: for er venstresiden og høyresiden ; for
er de og ; for er de og . Avstanden
vokser, aldri motsatt.
Legg merke til at valget ikke er entydig. og virker også.
Definisjonen krever bare at det finnes ett par som virker, ikke at du
finner det beste.
(Innstegsoppgave, sjanger C — kjøretidsfakta, altså et sant/usant-punkt om hvor
raskt noe går.) Avgjør om hvert utsagn er sant eller usant, og begrunn med én
setning.
a) er .
b) er .
c) er .
De to andre bokstavene
har to søsken. Du trenger dem sjelden på IN2010-eksamen, men de dukker opp i
emnebeskrivelsen og i pensumboka, og det er verdt å kunne skille dem fra
hverandre på et sant/usant-punkt.
slik at
Med ord: algoritmen bruker minst så mye tid. er den nedre grensen,
og brukes typisk om problemer heller enn om algoritmer — for eksempel at
sammenligningsbasert sortering krever sammenligninger.
samtidig: er både øvre og nedre grense, altså den nøyaktige vekstraten.
er , men bare — ikke .
Lille og lille er strenge versjoner av og («vokser
strengt saktere», «strengt raskere»). De brukes ikke i IN2010, verken i
oppgavetekster eller i sensorveiledninger.
Møter du dem i en generell algoritmebok, kan du hoppe over avsnittet. Det du
skal svare med på eksamen, er .
En algoritme bruker grunnsteg. Hvilke av disse utsagnene
er sanne?
a)
b)
c)
d)
(fordi og når ). Dette er det
strammeste -uttrykket, og det er dette du skal svare på eksamen.
b) Sant, men slapt. for , så en øvre grense på
holder også. Sensor ber om det strammeste uttrykket; svarer du
her, mister du poeng selv om påstanden i seg selv er sann.
c) Sant. for alle , så er en gyldig nedre
grense — også den slapp, men gyldig.
d) Usant. ville krevd at også er , og det er den
ikke: -leddet vokser raskere enn noen fast faktor ganger . Den riktige
tette grensen er .
Momentet å ta med videre: er en øvre grense og har lov til å være
romslig. Derfor er «er dette ?» et annet spørsmål enn «hva er
kjøretiden?». Eksamen spør nesten alltid om det siste, og forventer det
strammeste uttrykket.
Sant eller usant? Begrunn hvert svar med én setning.
a) Hvis , så er .
b) Hvis , så er .
c) En algoritme som er kan ikke ha kjøretid .
Hvert uttrykk vokser raskere enn alle som står til venstre for det. Rekkefølgen
er den mest brukte enkeltopplysningen i hele faget, og den skal sitte utenat:
den avgjør hvilket ledd som dominerer i en sum, hvilken algoritme som er best i
en poengtrapp, og hva som er riktig svar på et sant/usant-punkt.
Konsekvensen for forenkling: i en sum er det alltid det raskest voksende
leddet som bestemmer -klassen. er , fordi de to
siste leddene til slutt er forsvinnende små ved siden av det første.
Det leddet i en sum som vokser raskest, og som derfor alene bestemmer
-klassen. I er dominerende, og hele
uttrykket er .
Regelen brukes hver gang du analyserer kode med løkker etter hverandre: du
legger sammen, og beholder det verste.
De faste faktorene som forsvinner når du skriver : en algoritme med
steg og en med steg er begge , men den ene er femti ganger tregere i
praksis.
Dette er grunnen til at ikke kan brukes til å avgjøre hvilken av to
algoritmer som er raskest på en konkret, liten input — bare hvilken som til
slutt vinner når vokser.
strammeste -uttrykket for hvert:
- er en konstant: ingen i det hele tatt, altså .
- : siden , dominerer , og konstanten faller bort.
Altså .
- : her er det største leddet, fordi for
. Altså .
- : kvadratleddet dominerer, konstanten 4 faller bort. Altså .
- : dette er den som lurer flest. ser voldsomt ut, men
passerer den — allerede rundt er større, og deretter
drar den fra for godt. Altså .
Rekkefølgen fra saktest til raskest voksende:
altså , , , , .
Merk framgangsmåten, for den er den samme hver gang: finn det dominerende
leddet, stryk konstanten foran det, og skriv av det som står igjen. Ingen
tredje ting.
Oppgi det
strammeste -uttrykket for hvert av disse.
a)
b)
c)
d)
Fella som kommer igjen hvert år
Det finnes ett sant/usant-punkt som går igjen i settene i ulike forkledninger,
og som svært mange svarer feil på. Det ser slik ut:
«En algoritme med bedre asymptotisk kompleksitet bruker alltid færre
grunnsteg enn en med dårligere kompleksitet, på samme input.»
Svaret er usant, og grunnen ligger i de to bokstavene og fra
definisjonen.
At og sier kun at det finnes en
terskel der havner under og blir liggende der. Det sier ingenting
om hvem som er minst før den terskelen.
Et konkret par: la og . For er
mens — den «bedre» algoritmen
bruker over seksti ganger så mange steg. Først rundt tar igjen
, og fra da av vinner den for alltid.
Dette er grunnen til at praktiske sorteringsbiblioteker bytter til
innsettingssortering for korte lister, selv om den er : på små input er
den faktisk raskest.
Formuleringen du skal kjenne igjen: «bedre » betyr «vinner til slutt»,
ikke «vinner alltid».
At en algoritme har lavere -klasse enn en annen, garanterer bare at den er
raskest for store nok — ikke for all input. Skjulte konstanter kan gjøre
den «bedre» algoritmen langsommere på små datasett.
Dette er et fast sant/usant-punkt på eksamen, og svaret er alltid at påstanden
om «alltid færre steg» er usann.
Marker sant eller usant, og begrunn hvert svar med én setning.
a) En -algoritme bruker alltid færre grunnsteg enn en
-algoritme på samme input.
b) Et array kan sjekkes for om det er sortert i .
c) Hvis en algoritme har kjøretid , kan den ikke ha kjøretid
.
skjult konstant kan gjøre den asymptotisk bedre algoritmen tregere på små input.
b) Sant. Gå gjennom arrayet én gang og sammenlign hvert element med det
neste; du er ferdig etter sammenligninger, altså . Pseudokoden står
rett under her.
c) Usant. er en øvre grense, og en øvre grense kan gjøres
slappere. Alt som er er også — det er bare et mindre
informativt svar. Denne formuleringen er en klassisk felle fordi den høres
fornuftig ut.
Sensorblikket: på slike punkter er det ordet «alltid» i (a) og ordet «kan
ikke» i (c) som avgjør. Les sant/usant-utsagn ord for ord — det er den mest
gjentatte oppfordringen i sensorveiledningene.
A er et array med elementer, indeksertfra 0, slik at
A[0] er det første og A[n-1] det siste. Elementene kansammenlignes med
< og >.Prebetingelse: A inneholder elementer.
Postbetingelse: prosedyren returnerer true hvis og bare hvisA[0] <= A[1] <= ... <= A[n-1]; arrayet er uendret.
Procedure IsSorted(A)
Input: array A med n elementer, indeksert fra 0
Output: true hvis A er sortert stigende, ellers false
n = A.length
for i = 0 to n-2:
if A[i] > A[i+1]:
return false
return trueGrunnidé i én setning: et array er sortert nøyaktig når ingen nabopar står i
gal rekkefølge, så det holder å sjekke naboparene.
Kjøretid: løkka går høyst runder og gjør konstant arbeid i hver, så
kjøretiden er . Merk at den kan avslutte langt tidligere — finner den et
feil nabopar med én gang, stopper den etter én runde. Men beskriver det
verste tilfellet, og verst er at hele arrayet faktisk er sortert.
Se på pseudokoden for IsSorted over.
a) Hva er kjøretiden i verste tilfelle, og hvilken input gir det verste
tilfellet?
b) Hva er kjøretiden i beste tilfelle, og hvilken input gir det?
c) Er det riktig å si at IsSorted er ?
Verste, beste og forventet tilfelle
Oppgaven IsSorted viste at samme algoritme kan bruke svært ulik tid på ulik
input av samme størrelse. Derfor må du vite hvilket tilfelle du snakker om.
Hovedregelen i IN2010: oppgir du en kjøretid uten å presisere, mener du
verste tilfelle. Unntaket er noen få strukturer der forventet tilfelle er det
interessante, og der sier oppgaven det uttrykkelig — hashtabellen er det
viktigste eksempelet, og den kommer i Del 3.
Den største kjøretiden algoritmen kan få over alle input av størrelse .
Standardsvaret når en oppgave spør om «kjøretiden» uten å presisere.
Eksempel: kvikksortering er i verste tilfelle, selv om den nesten
alltid oppfører seg langt bedre.
Gjennomsnittlig kjøretid over inputene, eller over algoritmens egne tilfeldige
valg. Oppgis bare når oppgaven spør om det — men da er det viktig.
Eksempel: oppslag i en hashtabell er forventet og i verste
tilfelle. Begge tallene hører med i et fullstendig svar.
Den minste kjøretiden algoritmen kan få på en input av størrelse . Sjelden
det som spørres om, men nyttig for å forstå en algoritme — for eksempel at
innsettingssortering er på et allerede sortert array.
Fire feil koster poeng på nettopp dette stoffet, år etter år.
- Å tro at bedre betyr færre steg for all input. Det er faktisk feilen
som går igjen oftest, og den har sitt eget sant/usant-punkt nesten hvert år.
handler om store , punktum.
- Å blande øvre og tett grense. er (sant, men slapt) og
(presist). Er du bedt om kjøretiden, gi det strammeste -svaret.
- Å bruke eller . De finnes ikke i IN2010. Svar med .
- Å ta med konstanter og lavere ordensledd i svaret. «Kjøretiden er
» er ikke et galt regnestykke, men det er feil form: svaret
skal være .
Og en femte, som strengt tatt hører til hele faget: å bruke uten å si hva
er (dette er felle #10 i bokas register — å drøfte eller oppgi
kjøretid uten å definere problemstørrelsen). Én setning holder: « er antall
elementer i arrayet».
Du sammenligner to programmer som løser samme
oppgave. Program P bruker grunnsteg, program Q bruker
grunnsteg.
a) Oppgi -klassen for hvert program.
b) For hvilke er P faktisk raskest?
c) En kollega sier: «Q har best kompleksitet, så vi bruker Q.» Datasettene
deres har alltid rundt 50 elementer. Hva svarer du?
Avgjør sant eller usant, og begrunn hvert svar med én
setning.
a) .
b) .
c) .
d) Hvis og , så er .
En liten notasjonsvane du bør kjenne
IN2010 skriver med likhetstegn, slik denne boka har gjort hele
veien. Strengt tatt er en mengde av funksjoner, og det logisk
korrekte ville vært « tilhører ». Likhetstegnet er en gammel og fast
konvensjon i faget, og det er den formen du møter i oppgavetekster.
Praktisk betyr det bare én ting: likhetstegnet går ikke begge veier. Du kan
skrive , men ikke . Les det som «er» eller
«tilhører», ikke som «er lik».
Fagets faste skrivemåte. Leses « er » eller « tilhører », og
går bare én vei: er riktig, mens er meningsløst.
IN2010 bruker denne formen i oppgavetekster og sensorveiledninger, så du bør
kjenne den igjen — men ingen trekker deg for å skrive «tilhører».
De sju klassene du møter i dette faget
Nesten alle kjøretider i IN2010 lander i en av disse. Tabellen er verdt å kunne
utenat, både veien fra navn til uttrykk og veien fra uttrykk til et eksempel.
| -klasse | Navn | Typisk eksempel | Hva som skjer når dobles |
|---|---|---|---|
| konstant | slå opp A[5], legge til bakerst i et array | ingenting | |
| logaritmisk | binærsøk i et sortert array | ett steg til | |
| lineær | gå gjennom hele arrayet én gang | dobbelt så mye arbeid | |
| lineærlogaritmisk | flettesortering, heapsortering | litt mer enn dobbelt | |
| kvadratisk | sammenligne alle par, boblesortering | fire ganger så mye | |
| kubisk | tre nøstede løkker over samme mengde | åtte ganger så mye | |
| eksponentiell | prøve alle delmengder | kvadrering av arbeidet |
Den siste kolonnen er den mest nyttige på eksamen: den lar deg kontrollere et
svar på fem sekunder. Har du regnet ut at en algoritme er , men vet at
den bare bruker ett steg til når inputen dobles, har du regnet feil et sted.
dataene.
Eksempler i dette faget: oppslag på en indeks i et array, å lese det minste
elementet i en min-heap, å lese lengden av en liste.
inputen, får du bare ett steg til.
Kjennetegnet er at algoritmen kaster bort halvparten av søkeområdet i hvert
steg. Eksempler: binærsøk i et sortert array, innsetting i et balansert
søketre, sift-operasjonene i en heap.
innom hvert element et konstant antall ganger.
Eksempler: å sjekke om et array er sortert, å finne det største elementet, å
telle forekomster. Dette er ofte det beste som er mulig, siden du må lese
dataene minst én gang.
Kjennetegnet på en effektiv sammenligningsbasert sortering.
Eksempler: flettesortering, heapsortering og kvikksortering i forventet
tilfelle. Det er også den beviste nedre grensen for sortering som bare
sammenligner elementer.
element møter hvert annet. Dobles inputen, firedobles arbeidet.
Eksempler: boblesortering, innsettingssortering, og enhver «sammenlign alle par»-
løsning. På eksamen er nesten alltid det nederste trinnet i
poengtrappen — det gir uttelling, men aldri full pott.
arbeidet.
Dukker sjelden opp som en ønsket løsning, men er et vanlig riktig svar på en
kjøretidsoppgave der koden faktisk har tre nøstede løkker.
løsninger som prøver alle delmengder eller alle kombinasjoner.
Praktisk grense: rundt er slike algoritmer ubrukelige. I IN2010 møter
du dem mest som en rekursjon der hvert kall gjør to nye kall, og som
kontrasten til det som er praktisk mulig.
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 Universitetet i Oslo. Dette er ikke offisielt studiemateriell. Les mer.