F3 Komplexitetsanalys

 

  • Komplexitetsanalys
  • Linjärsökning
  • Binärsökning
  • Testning
  • Typkonvertering. 
  • typer i C

Denna föreläsning handlar om algoritmer. Vi börjar med att titta tillbaka på de två algoritmerna från förra förläsningen, inser och append


Komplexitetsanalys

Det är intressant att se tidsåtgången för en algoritm. Denna anges ofta som funktion av indatas storlek, som av tradition kallas n. Exempel: För sortering är LaTeX: nn antalet tal som ska sorteras.
Hur växer tidsåtgången LaTeX: T\left(n\right)T(n) för växande LaTeX: nn?

https://www.desmos.com/calculator Links to an external site.

n log(n) n*log(n) n2 2n
10 s 1 s 10 s 100 s 17 min
100 s 2 s 3 min 2 tim 1022 år
10000 s (ca 3 tim) 4 s 11 tim 3 år

Vi analyserar oftast värsta fallet (det är i regel enklare att räkna på) men man kan också räkna på medelfallet.

Istället för att ange den exakta tidsfunktionen LaTeX: T\left(n\right)T(n) nöjer vi oss med att ange ordoklassen LaTeX: O\left(n\right)O(n).

Definition

   LaTeX: T\left(n\right)T(n) är LaTeX: O\left(F\left(n\right)\right)O(F(n)) 

om det finns positiva konstanter LaTeX: cc och LaTeX: n_0n0 sådana att

LaTeX: 0\le T\left(n\right)\le c\cdot F\left(n\right)0T(n)cF(n)  för LaTeX: n\ge n_0nn0

Vad innebär detta?

  • LaTeX: c\cdot F\left(n\right)cF(n) anger en övre gräns för LaTeX: T\left(n\right)T(n) då LaTeX: nn är stort.
  • Vi behöver bara ta bara med den term som växer snabbast.
    • Om den snabbast växande termen är som mest ett polynom (t.ex. LaTeX: n^3n3) så anses algoritmen kunna utföras av en dator inom en rimlig tid. Exponentiella funktioner kan inte lösas på rimlig tid. 
  • Vi kan bortse från multiplikation med konstant.
  • Det spelar ingen roll vilken logaritm vi använder.

Exempel:

LaTeX: T\left(n\right)=10n^2\:+\:100n\:+\:\log_{10}n\:+1000T(n)=10n2+100n+log10n+1000    säger vi är    LaTeX: O\left(n^2\right)O(n2)

  • För små indata är analys onödig - använd den enklaste algoritmen!
  • Inläsning från fil tar längre tid än åtkomst av redan inlästa värden.
  • Minnesåtgång kan också vara relevant.

 

Uppgift: Matrismultiplikation

Vad är tidskomplexiteten för matrismultiplikation?


Sökning

Förutsättningar:

  • Vi söker efter något element i en lista med n element.
  • Det element vi söker efter karakteriseras av en söknyckel (eng key) men kan också ha andra data.

Frågor:

  • Vad ska hända om det sökta elementet inte finns med?
  • Kan det finnas flera element med samma nyckel? Vill man i så fall hitta alla?

Linjärsökning (Sequential search)

Den enklaste sökningen: bryter så fort den hittar det sökta elementet.

Algoritm:

  1. Gå igenom varje element i listan:
    • Jämför elementet med nyckeln, och
    • ...returnera True om dom är lika
  2. Returnera False om hela listan gåtts igenom utan att elementet hittats.

Linjärsökning är LaTeX: O\left(n\right)O(n) (i värsta fallet måste vi titta på alla LaTeX: nn elementen).

Här följer en funktion för linjärsökning i en lista.

def exists(the_list, key):
    for x in the_list:
        if x == key:
            return True
    return False

Uppgift: Förbättra funktionen

Den här funktionen talar bara om huruvida elementet finns med i listan.  Hur ska den modifieras för att returnera den plats i listan elementet finns? 


Binärsökning

Om listan är sorterad är den snabbaste sökningsalgoritmen binärsökning. Algoritm:

  1. Beräkna intervallets mittpunkt.
  2. Är det nyckeln? Avbryt, det sökta elementet är funnet.
  3. Annars: Avgör om det nyckeln finns i första eller andra halvan och fortsätt söka där (upprepa från punkt 1)
  4. Om halvan du söker i krympt till ingenting: Avbryt. Det sökta elementet fanns inte med.
11 13 13 20 22 25 28 30 31 32 32 48 62
11 13 13 20 22 25
20 22 25
25


Binärsökning är LaTeX: O\left(\log_2n\right)O(log2n) i värsta fallet. Varför det?

Vi söker bland n element och undrar hur många varv sökningen kan ta?

Antal element att söka bland halveras i varje varv, så första varvet får vi LaTeX: \frac{n}{2}n2, andra varvet LaTeX: \frac{n}{4}n4, tredje varvet LaTeX: \frac{n}{8}n8. Vi är klara när det bara finns ett element kvar att titta på och då är LaTeX: \frac{n}{2^x}=1n2x=1 där LaTeX: xx är antal varv. Vi två-logaritmerar bägge led och får att LaTeX: x=\log_2nx=log2n.
Här följer en funktion för binärsökning:

def binary_search(the_list, key):
low = 0
high = len(the_list)-1
found = False

while low <= high and not found:
middle = (low + high)//2
if the_list[middle] == key:
found = True
else:
if key < the_list[middle]:
high = middle - 1
else:
low = middle + 1
return found

Binärsökning är en knepig algoritm att implementera korrekt. Hur testar vi att koden ovan fungerar?

Testning

Här är några förslag! Testa:

  1. normalfallet, t ex att söka efter 14 i listan [9, 14, 23, 54, 92, 104]
  2. att söka efter ett tal som inte finns med, t ex 15
  3. att söka i en tom lista []
  4. att söka efter vänstraste elementet 9 ...
  5. ... och högraste elementet 104.
  6. att söka efter ett element bortom vänstra gränsen, t ex 8 ...
  7. ... och bortom högra gränsen, t ex 105.

Testmatris

Ett test består av ett hårdkodat testfall med ett förväntat resultat. När man utför testet jämför man testresultatet med det förväntade resultatet. Flera tester sätts upp i en matris där varje rad är ett test.

 

ID Namn Förutsättningar Testbeskrivning Förväntat resultat Utfall Har testet lyckats?
1 normalfall lista [1, 3, 5, 7]
sokt 3
söker efter 3 i listan 1

Typkonvertering

Det är skillnad på typer av variabler i python.

a = 1
b = 3.5
c = 'hej''

a + b  # fungerar

a + c # fungerar inte.  TypeError: unsupported operand type(s) for +: 'int' and 'str'

c + str(a) # fungerar, blir hej1

talstr = "123123"
talstr[0]  + talstr[2] #  blir strängn "13"
talstr[0:4] # från första till fjärde tecknet
a + int(talstr[0:4]) # 1232

 

Klasser i python

Flera variabler som har med varandra att göra kan man sätta samman i en klass. 

class Persondata:
   def __init__(self):
       self.name = ""
self.age = 0
self.weight = 0
self.length = 0
      

__init__ metoden är en specialmetod som konstruerar och initierar klassobjektet. self anger att det är en medlemsvariabel (ibland kallad fält eller atribut)  som blir tilldelad ett värde. 

a = Persondata()

a är ett objekt (eller en instans) av typen Persondata

Man kommer åt medlemsvariablerna med punktnotation

a.age = 73

Ofta vill man initiera samtidigt som man skapar objektet, det gör man genom att parametrisera __init__ metoden.

   def __init__(self, name, age, weight, length):
       self.name = name
self.age = age
self.weight = weight
self.length = length

Typer i C

I programmeringsspråket C måste programmeraren explicit skriva vilken typ en variabel ska ha. 

int a = 3:

float f = 3.14;

char * s = "hej"

C-kompilatorn behöver informationen för att reservera plats i minnet för variablerna.

Klasser i C kallas structar. 

struct Koordinat {
   int x;
   int y;
};

struct Koordinat p;
p.x = 1;
p.y = 2;

Man kan typdefiniera en ny typ med typedef