Lær lineært søk, binærsøk, boblesortering, innsettingssortering og utvalgssortering.
Søke- og sorteringsalgoritmer
Tenk deg at du har en telefonkatalog med 10 000 navn. Hvis du skal finne nummeret til «Olsen», kan du starte fra begynnelsen og sjekke hvert navn. Men det er jo ikke slik du faktisk bruker en telefonkatalog. Du slår opp omtrent midt i boken, ser at du er på «M», og vet at «O» er litt lenger bak. Deretter halverer du igjen og igjen til du finner riktig side. Denne intuitive metoden er faktisk en av de viktigste algoritmene i informatikk: binærsøk.
Søking og sortering er to av de mest grunnleggende operasjonene i informatikk. Praktisk talt alle programmer som arbeider med data, må søke i data og sortere data. E-postprogrammet ditt sorterer meldinger etter dato. Nettbutikken sorterer produkter etter pris. Søkemotorer søker gjennom milliarder av nettsider for å finne det du leter etter.
I dette kapittelet skal du lære å implementere de mest kjente søke- og sorteringsalgoritmene i Python, forstå hvordan de fungerer, og sammenligne dem med hensyn til effektivitet.
Lineært søk
Lineært søk er som å lete etter en bestemt bok i en usortert bokhylle. Du begynner med den første boken, sjekker om det er riktig bok, og hvis ikke, går du videre til neste. Du fortsetter til du finner boken eller har sjekket alle.
Algoritme:
1. Start fra det første elementet i listen
2. Sammenlign elementet med det du søker etter
3. Hvis det er likt, returner posisjonen
4. Hvis ikke, gå til neste element
5. Hvis du har sjekket alle elementer uten å finne, returner «ikke funnet»
def lineaert_sok(liste, sokeord):
"""Søker etter sokeord i listen. Returnerer indeksen eller -1."""
for i in range(len(liste)):
if liste[i] == sokeord:
return i # Funnet på posisjon i
return -1 # Ikke funnet
# Eksempel
tall = [4, 7, 2, 9, 1, 5, 8, 3, 6]
resultat = lineaert_sok(tall, 5)
if resultat != -1:
print(f"Fant 5 på posisjon {resultat}")
else:
print("Fant ikke 5")
resultat = lineaert_sok(tall, 10)
if resultat != -1:
print(f"Fant 10 på posisjon {resultat}")
else:
print("Fant ikke 10")Kjøring:
Fant 5 på posisjon 5
Fant ikke 10Analyse: For en liste med n elementer må lineært søk i gjennomsnitt sjekke n/2 elementer, og i verste fall alle n. Vi sier at lineært søk har tidskompleksitet O(n), der n er antall elementer. For en liste med 1 000 000 elementer kan det ta opptil 1 000 000 sammenligninger.
Binærsøk
Binærsøk er som å slå opp i en telefonkatalog. Fordi navnene er sortert alfabetisk, kan du halvere søkeområdet i hvert steg.
Algoritme:
1. Sett lav til 0 og hoy til siste indeks
2. Finn midt = (lav + hoy) // 2
3. Hvis elementet på midt er det du søker, returner midt
4. Hvis elementet på midt er for stort, sett hoy = midt - 1
5. Hvis elementet på midt er for lite, sett lav = midt + 1
6. Gjenta fra steg 2 så lenge lav <= hoy
7. Hvis lav > hoy, er elementet ikke i listen
def binaersok(sortert_liste, sokeord):
"""Binærsøk i en sortert liste. Returnerer indeksen eller -1."""
lav = 0
hoy = len(sortert_liste) - 1
while lav <= hoy:
midt = (lav + hoy) // 2
if sortert_liste[midt] == sokeord:
return midt # Funnet!
elif sortert_liste[midt] < sokeord:
lav = midt + 1 # Søk i høyre halvdel
else:
hoy = midt - 1 # Søk i venstre halvdel
return -1 # Ikke funnet
# Eksempel
sortert = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
print(binaersok(sortert, 7)) # 3 (posisjon 3)
print(binaersok(sortert, 12)) # -1 (ikke funnet)Trinnvis gjennomgang for å finne 7 i [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]:
| Steg | lav | hoy | midt | Verdi på midt | Handling |
|---|---|---|---|---|---|
| 1 | 0 | 9 | 4 | 9 | 9 > 7, hoy = 3 |
| 2 | 0 | 3 | 1 | 3 | 3 < 7, lav = 2 |
| 3 | 2 | 3 | 2 | 5 | 5 < 7, lav = 3 |
| 4 | 3 | 3 | 3 | 7 | Funnet! |
Bare 4 sammenligninger for å finne tallet i en liste med 10 elementer! For en liste med 1 000 000 elementer trenger binærsøk maksimalt 20 sammenligninger (log₂(1 000 000) ≈ 20), sammenlignet med 1 000 000 for lineært søk.
Binærsøk fungerer bare på sorterte lister! Hvis listen ikke er sortert, vil binærsøk gi feil svar. Hvis du trenger å søke i en usortert liste, har du to valg: (1) bruk lineært søk, eller (2) sorter listen først og bruk deretter binærsøk. Valg 2 lønner seg hvis du skal søke mange ganger i den samme listen, fordi sorteringen bare trenger å gjøres én gang.
Boblesortering (Bubble Sort)
Boblesortering er den enkleste sorteringsalgoritmen å forstå. Ideen er å gjentatte ganger gå gjennom listen og sammenligne naboelementer. Hvis to naboelementer er i feil rekkefølge, bytter vi dem. Vi gjentar dette til listen er sortert.
Navnet «boblesortering» kommer av at de største elementene gradvis «bobler opp» til riktig posisjon, akkurat som luftbobler stiger til overflaten i et glass vann.
def boblesortering(liste):
"""Sorterer en liste med boblesortering."""
n = len(liste)
for i in range(n - 1):
byttet = False
for j in range(n - 1 - i):
if liste[j] > liste[j + 1]:
# Bytt naboelementer
liste[j], liste[j + 1] = liste[j + 1], liste[j]
byttet = True
# Optimalisering: hvis ingen bytter ble gjort, er listen sortert
if not byttet:
break
return liste
# Eksempel
tall = [64, 34, 25, 12, 22, 11, 90]
print(f"Usortert: {tall}")
boblesortering(tall)
print(f"Sortert: {tall}")Kjøring:
Usortert: [64, 34, 25, 12, 22, 11, 90]
Sortert: [11, 12, 22, 25, 34, 64, 90]Trinnvis eksempel med [5, 3, 1, 4, 2]:
Gjennomgang 1: [3, 1, 4, 2, 5] (5 bobler opp til slutten)
Gjennomgang 2: [1, 3, 2, 4, 5] (4 på plass)
Gjennomgang 3: [1, 2, 3, 4, 5] (3 på plass)
Gjennomgang 4: [1, 2, 3, 4, 5] (ingen bytter, ferdig!)
Boblesortering er enkel og intuitiv, men den er treg for store datasett fordi den i verste fall trenger omtrent n² sammenligninger.
Innsettingssortering (Insertion Sort)
Innsettingssortering fungerer som du sorterer spillkort på hånden. Du tar ett kort om gangen fra bunken og setter det inn på riktig plass blant de kortene du allerede holder sortert.
Algoritme:
1. Start med det andre elementet (det første er «sortert» alene)
2. Ta elementet og sammenlign det med elementene til venstre
3. Flytt elementene som er større ett steg til høyre
4. Sett inn elementet på riktig plass
5. Gjenta for alle gjenværende elementer
def innsettingssortering(liste):
"""Sorterer en liste med innsettingssortering."""
for i in range(1, len(liste)):
nokkel = liste[i] # Elementet vi skal sette inn
j = i - 1
# Flytt elementer som er større enn nøkkelen
while j >= 0 and liste[j] > nokkel:
liste[j + 1] = liste[j]
j -= 1
# Sett inn nøkkelen på riktig plass
liste[j + 1] = nokkel
return liste
# Eksempel
tall = [5, 3, 1, 4, 2]
print(f"Usortert: {tall}")
innsettingssortering(tall)
print(f"Sortert: {tall}")Trinnvis for [5, 3, 1, 4, 2]:
| Steg | Nøkkel | Handling | Resultat |
|---|---|---|---|
| 1 | 3 | 3 < 5, flytt 5, sett inn 3 | [3, 5, 1, 4, 2] |
| 2 | 1 | 1 < 5, flytt 5; 1 < 3, flytt 3; sett inn 1 | [1, 3, 5, 4, 2] |
| 3 | 4 | 4 < 5, flytt 5; 4 > 3, sett inn 4 | [1, 3, 4, 5, 2] |
| 4 | 2 | 2 < 5, flytt; 2 < 4, flytt; 2 < 3, flytt; 2 > 1, sett inn | [1, 2, 3, 4, 5] |
Innsettingssortering er spesielt effektiv for lister som allerede er nesten sorterte, fordi den da gjør svært få flytteoperasjoner.
Utvalgssortering (Selection Sort)
Utvalgssortering er en annen enkel sorteringsalgoritme. Ideen er: finn det minste elementet og plasser det først. Finn deretter det nest minste og plasser det på posisjon 2, og så videre.
def utvalgssortering(liste):
"""Sorterer en liste med utvalgssortering."""
n = len(liste)
for i in range(n - 1):
# Finn indeksen til det minste elementet i resten av listen
min_indeks = i
for j in range(i + 1, n):
if liste[j] < liste[min_indeks]:
min_indeks = j
# Bytt det minste elementet med elementet på posisjon i
liste[i], liste[min_indeks] = liste[min_indeks], liste[i]
return liste
# Eksempel
tall = [29, 10, 14, 37, 13]
print(f"Usortert: {tall}")
utvalgssortering(tall)
print(f"Sortert: {tall}")Trinnvis for [29, 10, 14, 37, 13]:
| Steg | Finner minst | Bytte | Resultat |
|---|---|---|---|
| 1 | 10 (pos 1) | Bytt 29 og 10 | [10, 29, 14, 37, 13] |
| 2 | 13 (pos 4) | Bytt 29 og 13 | [10, 13, 14, 37, 29] |
| 3 | 14 (pos 2) | Allerede riktig | [10, 13, 14, 37, 29] |
| 4 | 29 (pos 4) | Bytt 37 og 29 | [10, 13, 14, 29, 37] |
Utvalgssortering gjør alltid nøyaktig n(n-1)/2 sammenligninger, uavhengig av om listen er sortert eller ikke. Den er enkel å forstå, men ikke spesielt effektiv.
Sammenligning av søke- og sorteringsalgoritmer
Søkealgoritmer:
| Algoritme | Krav | Verste fall | Kommentar |
|---|---|---|---|
| Lineært søk | Ingen | n sammenligninger | Enkel, fungerer alltid |
| Binærsøk | Sortert liste | log₂(n) sammenligninger | Svært rask for store datasett |
For å illustrere forskjellen: i en liste med 1 000 000 elementer gjør lineært søk opptil 1 000 000 sammenligninger, mens binærsøk gjør maksimalt 20!
Sorteringsalgoritmer:
| Algoritme | Verste fall | Beste fall | Stabil? | Kommentar |
|---|---|---|---|---|
| Boblesortering | n² | n (optimalisert) | Ja | Enklest å forstå |
| Innsettingssortering | n² | n | Ja | Best for nesten sorterte data |
| Utvalgssortering | n² | n² | Nei | Færrest bytteoperasjoner |
Alle tre sorteringsalgoritmene har tidskompleksitet O(n²) i verste fall, noe som betyr at de blir svært trege for store datamengder. I praksis bruker Python den innebygde funksjonen sorted() eller metoden .sort(), som bruker Timsort-algoritmen med tidskompleksitet O(n log n), noe som er vesentlig raskere.
# Pythons innebygde sortering (Timsort) – bruk denne i praksis!
tall = [64, 34, 25, 12, 22, 11, 90]
sortert = sorted(tall) # Lager ny sortert liste
tall.sort() # Sorterer listen direkteLikevel er det verdifullt å forstå de enklere algoritmene, fordi de illustrerer grunnleggende konsepter som sammenligning, bytting og iterasjon, og fordi de er et godt utgangspunkt for å forstå algoritmekompleksitet.
Lag et program som leser inn en liste med elevnavn, sorterer den alfabetisk med innsettingssortering, og lar brukeren søke etter et navn med binærsøk.
def innsettingssortering(liste):
for i in range(1, len(liste)):
nokkel = liste[i]
j = i - 1
while j >= 0 and liste[j].lower() > nokkel.lower():
liste[j + 1] = liste[j]
j -= 1
liste[j + 1] = nokkel
return liste
def binaersok(sortert_liste, sokeord):
lav = 0
hoy = len(sortert_liste) - 1
while lav <= hoy:
midt = (lav + hoy) // 2
if sortert_liste[midt].lower() == sokeord.lower():
return midt
elif sortert_liste[midt].lower() < sokeord.lower():
lav = midt + 1
else:
hoy = midt - 1
return -1
# Les inn elevnavn
elever = ["Sara", "Ole", "Anna", "Erik", "Lise", "Kari", "Per"]
print(f"Original: {elever}")
# Sorter
innsettingssortering(elever)
print(f"Sortert: {elever}")
# Søk
navn = input("\nSøk etter navn: ")
pos = binaersok(elever, navn)
if pos != -1:
print(f"Fant {elever[pos]} på posisjon {pos + 1}")
else:
print(f"{navn} finnes ikke i listen")Kjøring:
Original: ['Sara', 'Ole', 'Anna', 'Erik', 'Lise', 'Kari', 'Per']
Sortert: ['Anna', 'Erik', 'Kari', 'Lise', 'Ole', 'Per', 'Sara']
Søk etter navn: Kari
Fant Kari på posisjon 3Vi bruker .lower() i sammenligningene for å gjøre sorteringen og søket uavhengig av store/små bokstaver.
Hva er hovedforskjellen mellom lineært søk og binærsøk?
Hvor mange sammenligninger trenger binærsøk maksimalt for å finne et element i en sortert liste med 1024 elementer?
I boblesortering, hva skjer i den første gjennomgangen av listen [5, 3, 8, 1, 4]?
Gå gjennom binærsøk steg for steg for å finne tallet 13 i listen [2, 5, 8, 13, 17, 21, 25, 30]. Skriv ned verdiene for lav, hoy og midt i hvert steg.
Implementer en funksjon i Python som bruker utvalgssortering til å sortere en liste med ordbøker etter en gitt nøkkel. For eksempel skal listen [{"navn": "Sara", "alder": 17}, {"navn": "Ole", "alder": 16}] kunne sorteres etter "alder" eller "navn".
Skriv et Python-program som sammenligner hastigheten til lineært søk og binærsøk. Programmet skal lage en sortert liste med 100 000 tall, søke etter et bestemt tall med begge metoder, og telle antall sammenligninger hver metode gjør.
Hvilken sorteringsalgoritme er mest effektiv for en liste som allerede er nesten sortert (f.eks. bare 2-3 elementer er på feil plass)?
Oppsummering
I dette kapittelet har du lært:
- Lineært søk: sjekker hvert element i rekkefølge.
- Binærsøk: halverer søkeområdet, krever sortert liste.
- Boblesortering: bytter naboelementer gjentatte ganger.
- Innsettings- og utvalgssortering: andre enkle sorteringsalgoritmer.
- Sammenligning: binærsøk er mye raskere enn lineært på store lister.
Noekkelbegreper
| Begrep | Forklaring |
|---|---|
| Lineært søk | Sjekker elementene ett etter ett |
| Binærsøk | Halverer søkeområdet i sortert liste |
| Boblesortering | Sortering ved å bytte naboelementer |
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.