DD1320 Tillämpad Datalogi

Föreläsning 4: Komplexitetsanalys, sökning


FYRVERKERIKONSERT IKVÄLL KL 19-21 PÅ BORGGÅRDEN


Utskrift av binärträd: inorder, preorder, postorder

Om man ska skriva ut alla talen i trädet vill man oftast göra det i så kallad inordning (eng. inorder), dvs från vänster till höger.
Fråga: Hur skriver man ut trädet i inordning?
Rekursivt svar: Först skriver man ut vänsterträdet, sedan rottalet, sist högerträdet.
...men ett tomt träd skriver man inte alls.
Följande funktion gör att write(root) skriver ut 1 17 666 4711 9999 för vårt träd.

#Inordning
    def write(p):
        if p != None:
            write(p.left)
            print p.value
            write(p.right)
Om man kastar om dom tre sista satserna får man ändå ut alla talen på skärmen men i andra ordningar. Preordning (eng. preorder) innebär att rottalet skrivs först, sedan vänsterträdet och sist högerträdet. I vårt exempel blir ordningen 4711   17   1   666   9999.

Om vi återgår till orkesterträdet kan vi se att preordning faktiskt ger vettigare utskrift. Så här blir koden i det fallet.

#Preordning     
    def write(p):
        if p != None:
            print p.value
            write(p.down)
            write(p.right)
Utskriften blir då den naturliga. Om vi för tydlighets skull använder indragning av orden på lägre nivå blir utskriften
    Orkester              
        Blås
            Trä
            Bleck
        Stråk
            Vi
            Va
            Vc
            Kb
        Slag
(Hur gör man för att få dessa indragningar?)

Slutligen kan man skriva ut i postordning (eng. postorder) och det innebär att vänsterträdet skrivs först, sedan högerträdet och sist roten. Det ger 1   666   17   9999   4711 i vårt exempel.


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 n antalet tal som ska sorteras.
Hur växer tidsåtgången T(n) för växande n?

            n             log(n)               nlog(n)               n2                 2n        
1010 s1 s10 s100 s17 min
100100 s2 s3 min2 tim1022 år
1000010000 s (ca 3 tim)4 s11 tim3 å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 T(n) nöjer vi oss med att ange ordoklassen O(n).



Definition 
T(n) är O(F(n)) om det finns positiva konstanter c och n0 sådana att 0<=T(n)<=cF(n) för n>=n0
Vad innebär detta? Exempel: T(n) = 10n2 + 100n + 10logn + 1000 säger vi är O(n2).

Uppgift: Matrismultiplikation

Vad är komplexiteten för matrismultiplikation?

Sökning

Förutsättningar: Frågor:

Linjärsökning (Sequential search)

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

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

def linjarsokning(listan, nyckel):
    for x in listan:
        if x == nyckel:
            return True
    return False



Binärsökning

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




11131320222528303132324862

111313202225                             

            202225                             

                    25                             

Binärsökning är O(log n) i värsta fallet:
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 n/2, andra varvet n/4, tredje varvet n/8. Vi är klara när det bara finns ett element kvar att titta på och då är n/2x=1 där x är antal varv. Vi två-logaritmerar bägge led och får att x=2log(n).
Här följer en funktion för binärsökning:

def binsok(listan, nyckel):
"""Söker i "listan" efter "nyckel". Returnerar True om den hittas, False annars"""
    vanster = 0
    hoger = len(listan)-1
    found = False

    while vanster <= hoger and not found:
        mitten = (vanster + hoger)/2
        if listan[mitten] == nyckel:
	    found = True
        else:
            if nyckel < listan[mitten]:
                hoger = mitten-1
            else:
                vanster = mitten+1
    return found