Lær lineært søk, binærsøk, boblesortering, innsettingssortering og utvalgssortering.
Søke- og sorteringsalgoritmar
Tenk deg at du har ein telefonkatalog med 10 000 namn. Viss du skal finne nummeret til «Olsen», kan du starte frå byrjinga og sjekke kvart namn. Men det er jo ikkje slik du faktisk brukar ein telefonkatalog. Du slår opp omtrent midt i boka, ser at du er på «M», og veit at «O» er litt lenger bak. Deretter halverer du igjen og igjen til du finn rett side. Denne intuitive metoden er faktisk ein av dei viktigaste algoritmane i informatikk: binærsøk.
Søking og sortering er to av dei mest grunnleggjande operasjonane i informatikk. Praktisk talt alle program som arbeider med data, må søkje i data og sortere data. E-postprogrammet ditt sorterer meldingar etter dato. Nettbutikken sorterer produkt etter pris. Søkjemotorar søkjer gjennom milliardar av nettsider for å finne det du leitar etter.
I dette kapittelet skal du lære å implementere dei mest kjende søke- og sorteringsalgoritmane i Python, forstå korleis dei fungerer, og samanlikne dei med omsyn til effektivitet.
Lineært søk
Lineært søk er som å leite etter ei bestemt bok i ei usortert bokhylle. Du byrjar med den første boka, sjekkar om det er rett bok, og viss ikkje, går du vidare til neste. Du held fram til du finn boka eller har sjekka alle.
Algoritme:
1. Start frå det første elementet i lista
2. Samanlikn elementet med det du søkjer etter
3. Viss det er likt, returner posisjonen
4. Viss ikkje, gå til neste element
5. Viss du har sjekka alle element utan å finne, returner «ikkje funne»
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 ei liste med n element må lineært søk i gjennomsnitt sjekke n/2 element, og i verste fall alle n. Vi seier at lineært søk har tidskompleksitet O(n), der n er talet på element. For ei liste med 1 000 000 element kan det ta opptil 1 000 000 samanlikningar.
Binærsøk
Binærsøk er som å slå opp i ein telefonkatalog. Fordi namna er sortert alfabetisk, kan du halvere søkjeområdet i kvart steg.
Algoritme:
1. Set lav til 0 og hoy til siste indeks
2. Finn midt = (lav + hoy) // 2
3. Viss elementet på midt er det du søkjer, returner midt
4. Viss elementet på midt er for stort, set hoy = midt - 1
5. Viss elementet på midt er for lite, set lav = midt + 1
6. Gjenta frå steg 2 så lenge lav <= hoy
7. Viss lav > hoy, er elementet ikkje i lista
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! |
Berre 4 samanlikningar for å finne talet i ei liste med 10 element! For ei liste med 1 000 000 element treng binærsøk maksimalt 20 samanlikningar (log₂(1 000 000) ≈ 20), samanlikna med 1 000 000 for lineært søk.
Binærsøk fungerer berre på sorterte lister! Viss lista ikkje er sortert, vil binærsøk gi feil svar. Viss du treng å søkje i ei usortert liste, har du to val: (1) bruk lineært søk, eller (2) sorter lista først og bruk deretter binærsøk. Val 2 lønner seg viss du skal søkje mange gonger i den same lista, fordi sorteringa berre treng å gjerast éin gong.
Boblesortering (Bubble Sort)
Boblesortering er den enklaste sorteringsalgoritmen å forstå. Ideen er å gjentekne gonger gå gjennom lista og samanlikne naboelement. Viss to naboelement er i feil rekkefølgje, byter vi dei. Vi gjentek dette til lista er sortert.
Namnet «boblesortering» kjem av at dei største elementa gradvis «boblar opp» til rett posisjon, akkurat som luftboblar stig til overflata i eit glas vatn.
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 boblar 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 byte, ferdig!)
Boblesortering er enkel og intuitiv, men han er treg for store datasett fordi han i verste fall treng omtrent n² samanlikningar.
Innsetjingssortering (Insertion Sort)
Innsetjingssortering fungerer som du sorterer spelkort på handa. Du tek eitt kort om gongen frå bunken og set det inn på rett plass blant dei korta du allereie held sorterte.
Algoritme:
1. Start med det andre elementet (det første er «sortert» åleine)
2. Ta elementet og samanlikn det med elementa til venstre
3. Flytt elementa som er større eitt steg til høgre
4. Set inn elementet på rett plass
5. Gjenta for alle attståande element
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] |
Innsetjingssortering er spesielt effektiv for lister som allereie er nesten sorterte, fordi han då gjer svært få flytteoperasjonar.
Utvalssortering (Selection Sort)
Utvalssortering er ein annan 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å vidare.
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] |
Utvalssortering gjer alltid nøyaktig n(n-1)/2 samanlikningar, uavhengig av om lista er sortert eller ikkje. Han er enkel å forstå, men ikkje spesielt effektiv.
Samanlikning av søke- og sorteringsalgoritmar
Søkjealgoritmar:
| Algoritme | Krav | Verste fall | Kommentar |
|---|---|---|---|
| Lineært søk | Ingen | n samanlikningar | Enkel, fungerer alltid |
| Binærsøk | Sortert liste | log₂(n) samanlikningar | Svært rask for store datasett |
For å illustrere skilnaden: i ei liste med 1 000 000 element gjer lineært søk opptil 1 000 000 samanlikningar, medan binærsøk gjer maksimalt 20!
Sorteringsalgoritmar:
| Algoritme | Verste fall | Beste fall | Stabil? | Kommentar |
|---|---|---|---|---|
| Boblesortering | n² | n (optimalisert) | Ja | Enklast å forstå |
| Innsetjingssortering | n² | n | Ja | Best for nesten sorterte data |
| Utvalssortering | n² | n² | Nei | Færrast byteoperasjonar |
Alle tre sorteringsalgoritmane har tidskompleksitet O(n²) i verste fall, noko som betyr at dei blir svært trege for store datamengder. I praksis brukar Python den innebygde funksjonen sorted() eller metoden .sort(), som brukar Timsort-algoritmen med tidskompleksitet O(n log n), noko som er vesentleg raskare.
# 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å dei enklare algoritmane, fordi dei illustrerer grunnleggjande konsept som samanlikning, byting og iterasjon, og fordi dei er eit godt utgangspunkt for å forstå algoritmekompleksitet.
Lag eit program som les inn ei liste med elevnamn, sorterer ho alfabetisk med innsetjingssortering, og lèt brukaren søkje etter eit namn 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 brukar .lower() i samanlikningane for å gjere sorteringa og søket uavhengig av store/små bokstavar.
Kva er hovudskilnaden mellom lineært søk og binærsøk?
Kor mange samanlikningar treng binærsøk maksimalt for å finne eit element i ei sortert liste med 1024 element?
I boblesortering, kva skjer i den første gjennomgangen av lista [5, 3, 8, 1, 4]?
Gå gjennom binærsøk steg for steg for å finne talet 13 i lista [2, 5, 8, 13, 17, 21, 25, 30]. Skriv ned verdiane for lav, hoy og midt i kvart steg.
Implementer ein funksjon i Python som brukar utvalssortering til å sortere ei liste med ordbøker etter ein gitt nøkkel. Til dømes skal lista [{"navn": "Sara", "alder": 17}, {"navn": "Ole", "alder": 16}] kunne sorterast etter "alder" eller "navn".
Skriv eit Python-program som samanliknar farten til lineært søk og binærsøk. Programmet skal lage ei sortert liste med 100 000 tal, søkje etter eit bestemt tal med begge metodar, og telje talet på samanlikningar kvar metode gjer.
Kva for ein sorteringsalgoritme er mest effektiv for ei liste som allereie er nesten sortert (t.d. berre 2-3 element er på feil plass)?
Oppsummering
I dette kapittelet har du lært:
- Lineaert søk: sjekkar kvart element i rekkefølge.
- Binaersoek: halverer soekeomraadet, krev sortert liste.
- Boblesortering: byter naboelement gjentekne gonger.
- Innsetjings- og utvalssortering: andre enkle sorteringsalgoritmar.
- Samanlikning: binaersoek er mykje raskare enn lineaert på store lister.
Noekkelbegreper
| Begrep | Forklaring |
|---|---|
| Lineaert søk | Sjekkar elementa eitt etter eitt |
| Binaersoek | Halverer soekeomraadet i sortert liste |
| Boblesortering | Sortering ved å byte naboelement |
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.