Tilbake
3.4
Søke- og sorteringsalgoritmer

3.4 Søke- og sorteringsalgoritmer

Lær lineært søk, binærsøk, boblesortering, innsettingssortering og utvalgssortering.

60 min
7 oppgaver
Lineært søkBinærsøkBoblesorteringInnsettingssortering
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 7 oppgaver

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 (også kalla sekvensielt søk) er den enklaste søkjealgoritmen. Han startar frå byrjinga av lista og sjekkar kvart element i rekkefølgje til han anten finn det søkte elementet eller har gått gjennom heile lista utan å finne det. Lineært søk fungerer på alle lister, uavhengig av om dei er sorterte eller ikkje. I verste fall (elementet er sist eller ikkje finst) må han sjekke alle n element, noko som gjer han treg for svært store datasett.

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 10

Analyse: 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 ein svært effektiv søkjealgoritme som krev at lista er sortert på førehand. Algoritmen samanliknar det søkte elementet med midtelementet i lista. Viss det søkte er mindre, held søket fram i venstre halvdel. Viss det er større, held søket fram i høgre halvdel. Slik blir søkjeområdet halvert for kvart steg. For ei sortert liste med n element treng binærsøk maksimalt log₂(n) samanlikningar, noko som er dramatisk raskare enn lineært søk for store datasett.

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]:

SteglavhoymidtVerdi på midtHandling
109499 > 7, hoy = 3
203133 < 7, lav = 2
323255 < 7, lav = 3
43337Funnet!

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.

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]:

StegNøkkelHandlingResultat
133 < 5, flytt 5, sett inn 3[3, 5, 1, 4, 2]
211 < 5, flytt 5; 1 < 3, flytt 3; sett inn 1[1, 3, 5, 4, 2]
344 < 5, flytt 5; 4 > 3, sett inn 4[1, 3, 4, 5, 2]
422 < 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]:

StegFinner minstBytteResultat
110 (pos 1)Bytt 29 og 10[10, 29, 14, 37, 13]
213 (pos 4)Bytt 29 og 13[10, 13, 14, 37, 29]
314 (pos 2)Allerede riktig[10, 13, 14, 37, 29]
429 (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:

AlgoritmeKravVerste fallKommentar
Lineært søkIngenn samanlikningarEnkel, fungerer alltid
BinærsøkSortert listelog₂(n) samanlikningarSvæ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:
AlgoritmeVerste fallBeste fallStabil?Kommentar
Boblesorteringn (optimalisert)JaEnklast å forstå
InnsetjingssorteringnJaBest for nesten sorterte data
UtvalssorteringNeiFæ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 direkte

Likevel 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.

✏️Praktisk bruk: sortering og søking saman

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 3

Vi brukar .lower() i samanlikningane for å gjere sorteringa og søket uavhengig av store/små bokstavar.

📝Oppgave 3.4.1

Kva er hovudskilnaden mellom lineært søk og binærsøk?

📝Oppgave 3.4.2

Kor mange samanlikningar treng binærsøk maksimalt for å finne eit element i ei sortert liste med 1024 element?

📝Oppgave 3.4.3

I boblesortering, kva skjer i den første gjennomgangen av lista [5, 3, 8, 1, 4]?

📝Oppgave 3.4.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.

📝Oppgave 3.4.5

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".

📝Oppgave 3.4.6

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.

📝Oppgave 3.4.7

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


BegrepForklaring
Lineaert søkSjekkar elementa eitt etter eitt
BinaersoekHalverer soekeomraadet i sortert liste
BoblesorteringSortering 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.