Presentasjon lastes. Vennligst vent

Presentasjon lastes. Vennligst vent

Alg. Dat Øvingsforelesning 5 Kompleksitetsanalyse Torbjørn Moralnd

Liknende presentasjoner


Presentasjon om: "Alg. Dat Øvingsforelesning 5 Kompleksitetsanalyse Torbjørn Moralnd"— Utskrift av presentasjonen:

1 Alg. Dat Øvingsforelesning 5 Kompleksitetsanalyse Torbjørn Moralnd

2 Dagens tema Motivasjon  -notasjon O- og  -notasjon Relasjoner mellom O,  og  Litt om kompleksitetsklasser Rekursive algoritmer Kjøretidsanalyse Rekurrensregning Øving 4: Prinsessejakt Øving 5: Veibygging i Ogligogo

3 Motivasjon Vi ønsker å måle hvor rask en algoritme er Lite mening i å måle kjøretid i sekunder Forskjeller i programmeringsspråk og maskinvare Kjøretiden kan variere drastisk med dataene algoritmen blir brukt på Datamaskiner blir kraftigere, og algoritmer vil bli brukt på større data Hvordan ser kjøretiden ut når inputstørrelsen nærmer seg uendelig? ::

4 Analyse Vi trenger et matematisk uttrykk for hva kjøretiden blir, gitt inputstørrelsen – altså tiden som en funksjon av inputstørrelsen Vi analyserer trinnene i algoritmen for i in xrange(n): doSomething() for i in xrange(n): for j in xrange(n): doSomethingElse() Kjøretid: f(n) = c 1 · n + c 2 · n 2, hvor c 1 er kjøretiden til doSomething(), og c 2 er kjøretiden til doSomethingElse() ::

5 Største ledd c 1 og c 2 kommer an på maskinvaren La oss anta at c 1 = 100 og c 2 = 2 Når bare n blir stor nok ( n > 50 ), blir 2n 2 større enn 100n, og når n vokser mer og mer, blir 2n 2 MYE større enn 100n Kun det største leddet ( 2n 2 ) er interessant, fordi dette leddet vil dominere de andre når n blir stor nok Siden konstanten foran n 2 kan variere fra maskin til maskin, kutter vi ut den også ::

6  -notasjon Hvordan uttrykke dette? Vi sier at 2n n =  (n 2 ) Viktig:  (n 2 ) er en mengde!  (n 2 ) består av alle funksjoner som vokser ”like raskt” som n 2 når n går mot uendelig Likhetstegnet misbrukes – det skulle egentlig ha vært f(n)   (g(n)) f(n) =  (g(n)) betyr altså: ” f(n) er en av de funksjonene som vokser like raskt som g(n) ” ::

7 Definisjon  (g(n)) = {f(n) : det finnes positive konstanter c 1, c 2 og n 0 slik at 0  c 1 g(n)  f(n)  c 2 g(n) for alle n  n 0 } Altså:  (g(n)) består av alle funksjoner som g(n) kan brukes som både øvre og nedre grense for Hvis vi skal vise at f(n) =  (g(n)), må vi bevise ulikhetene og finne c 1, c 2 og n 0 ::

8 Eksempel – polynomer Gitt f(n) = n 3 – 100n 2 + n Vi trikser med leddene: f(n) = n 3 – 100n 2 + n  n 3 + n  n 3 + n 3 = 2n 3 f(n) = n 3 – 100n 2 + n  n 3 – n 3 / 2 + n  n 3 / 2 Vi finner ut n å r overgangene gjelder: – 100n 2  0 : uansett n  n 3 : for n  1 – 100n 2  – n 3 / 2 : for n  200 n  0 : for n  0 Alts å kan vi sette n 0 = 200 ::

9 Eksempel – polynomer Nå vet vi at 0  n 3 / 2  f(n)  2n 3 når n > n 0 = 200 Vi kan nå sette c 1 = ½, c 2 = 2 og g(n) = n 3 Kravene for at f(n) =  (g(n)) er oppfylt Altså er n 3 – 100n 2 + n =  (n 3 ) ::

10 Grafisk fremstilling 2n 3 n 3 – 100n 2 + n n 3 / 2 ::

11 Grafisk fremstilling 2n 3 n 3 – 100n 2 + n n 3 / 2 ::

12 Grafisk fremstilling 2n 3 n 3 – 100n 2 + n n 3 / 2 ::

13 Grafisk fremstilling 2n 3 n 3 – 100n 2 + n n 3 / 2 ::

14 O- og  -notasjon f(n) =  (g(n)) sier at g er b å de en ø vre og en nedre grense for f Hvis vi bare vil si at g er en ø vre grense for f, bruker vi O-notasjon: f(n) = O(g(n)) Hvis vi bare vil si at g er en nedre grense for f, bruker vi  -notasjon: f(n) =  (g(n)) Disse grensene er ikke tette: f.eks er n = O(2 n ), og n 100 =  (n) Se Cormen kap. 3.1 for definisjoner. Regning med O og  er helt tilsvarende det vi gjorde med  ::

15 Relasjoner mellom O,  og  f(n) = O(g(n))  g(n) =  (f(n)) f(n) =  (g(n))  f(n) = O(g(n))  f(n) =  (g(n)) f(n) =  (g(n))  g(n) =  (f(n))   (f(n)) =  (g(n))  (f(n)) = O(f(n))   (f(n) Se side 49 i Cormen for nyttige relasjoner Prøv å bevise disse selv! Bruk definisjonene av O (side 44),  (side 45) og  (side 42) ::

16 Kompleksitetsklasser Grovinndeling i stigende rekkefølge: Konstant: 1 Logaritmisk: log b n Polynomisk: n k Eksponentiell: 2 n Faktoriell: n! Alt som er enda verre, f.eks. n n ::

17 Kompleksitetsklasser Eksempler – alle på samme linje er ”like raske” (de er  av hverandre) 1, 2, e, lg n, ln n, log 10 n, lg n 100 (lg n) 2, (ln n) 2, (log 10 n) 2, (lg n 100 ) 2 n, n lg n n lg n, n log 42 n n 2 2 n 3 n n! n n ::

18 Fallgruver Grunntallet til en logaritme har ikke noe å si for kompleksiteten: lg a n =  (lg b n) Grunntallet til en potens har mye å si for kompleksiteten: a n   (b n ) hvis a  b Er 2 n + c =  (2 n ) ? Er 2 cn =  (2 n ) ? Vær forsiktig med transitivitet: Følgende er korrekt: f(n) = O(g(n))  g(n) = O(h(n))  f(n) = O(h(n)) Men kan vi slutte noe av det følgende? f(n) = O(g(n))  g(n) =  (h(n)) ::

19 Fallgruver Ikke alle funksjoner kan sammenlignes med O,  og  Eksempel: n og n 1 + sin n 1 + sin n oscillerer mellom 0 og 2, så n 1 + sin n veksler hele tiden mellom å være større enn og mindre enn n O angir en mengde funksjoner Det er ikke i seg selv et mål på worst case- kjøretid, selv om det ofte brukes til å angi dette Å si ”kjøretiden er minst O(n) ” er meningsløst Det samme gjelder for  og best case-kjøretid ::

20 Fallgruver O,  og  er rent matematiske konsepter De beskriver funksjoner, og bryr seg ikke om hva funksjonene representerer Derfor: O er ikke knyttet til worst case,  er ikke knyttet til best case, og  er ikke knyttet til algoritmer hvor worst case = best case Men: O brukes ofte for å angi kjøretiden i worst case, og  brukes ofte for best case Merk at hvis en algoritme er O(f(n)) i worst case og  (g(n)) i best case, er algoritmen O(f(n)) og  (g(n)) i alle tilfeller ::

21 Pseudopolynomialitet Gitt en algoritme som tar tallet n som input og har kjøretid O(n) – hvilken kompleksitetsklasse er dette? n betegner her ikke størrelsen på input, men er selv en del av inputen Størrelsen til n = antall bits som kreves = lg n n = 2 lg n = 2 w Oi sann – eksponentiell kjøretid! Dukker ofte opp som lureoppgave på eksamen! ::

22 Pseudopolynomialitet Merk: omskrivningen på forrige side ( n = 2 lg n ) er det alltid lov å foreta – spørsmålet er bare hvilken form som er mest hensiktsmessig: Hvis n faktisk beskriver inputstørrelsen, bør uttrykket baseres på n Hvis n er et tall som er en del av input, bør uttrykket baseres på lg n Eksempel fra eksamen 2006: En algoritme for å sjekke om tallet n er et primtall er  (lg n). Er dette subpolynomisk? Nei, siden inputstørrelsen er lg n, så dette er en lineær kjøretid ifht. inputstørrelsen ::

23 Pseudopolynomialitet Til de oppvakte som sier "men en talliste av lengde n består jo av tallene a1, a2,..., an – bør ikke størrelsen på disse tallene tas med i beregningen?" Bra observasjon! Strengt tatt burde de det, men det hadde ført til ekstremt tungvinte uttrykk I alle situasjoner vi vil komme borti vil vi anta at alle tallene i en liste er av begrenset størrelse (typisk 32 eller 64 bit) og således opptar konstant plass ::

24 Hvordan velge algoritme? Analyser algoritmene du vurderer å bruke Finn ut hvordan inputen din forventes å være (vil det oftest være best case, average case eller worst case?) Hvor stor forventes inputen å være? Vil den være så liten at konstantleddene blir viktige? (I sortering går man ofte over til insertion sort når listene er små nok.) Har du råd til worst case-kjøretiden? (dette har du ikke alltid i real-time-applikasjoner)

25 Kjøretidsanalyse av rekursive algoritmer En algoritme er rekursiv hvis den kaller seg selv en eller flere ganger Kjøretidsanalyse av rekursive algoritmer består av fire steg 1. Velg en metrikk som indikerer inputstørrelse 2. Bestem algoritmens grunnleggende operasjonsfunksjon f(n) som en funksjon av inputstørrelsen 3. Sett opp en rekurrensligning T(n) =...T(...) f(n), T(1) = Løs rekurrensen på en eller en annen måte

26 Rekurrensregning Iterasjonsmetoder Foroversubstitusjon Bakoversubstitusjon Variabelskifte Substitusjonsmetoden Tremetoden Masterteoremet

27 Foroversubstitusjon Ganske rett frem Regner T(1), T(2), T(3) osv til vi ser et generelt mønster Løsningen kommer ved å finne ut hva det n- te elementet blir

28 Tower of Hanoi Gitt tre staver (A,B,C) og N klosser. Klossene skal flyttes fra stav A til stav C via stav B. Det er forbudt å sette en større kloss opp på en som er mindre. Man kan bare flytte en kloss om gangen Hvor mange flytt trenger man, og hvordan går man frem?

29 Tower of Hanoi Løsning: def Hanoi (N, A, B, C) : if N > 1 : Hanoi (N−1, A, C, B) print "Move one disk from " + A + " to " + C Hanoi (N−1, B, A, C) else : print "Move one disk from " + A + " to " + C

30 Tower of Hanoi 1. Inputstørreslse: hvor mange disker som skal flyttes, N 2. Operasjonskostnadene er å skrive ut at vi flytter en disk – f(n) = 1 3. For hver Hanoi(N, …) kalles Hanoi(N-1, …) nøyaktig to ganger –T(N) = 2T(N-1) + 1, T(1) = 1 4. Da gjenstår det bare å løse dette…

31 Tower of Hanoi Finner T(2) ved hjelp av T(1), T(3) ved hjelp av T(2) osv: T(1) = 1 T(2) = 2*T(1) + 1 = = 3 T(3) = 2*T(2) + 1 = = 7 T(4) = 2*T(3) + 1 = = 15

32 Tower of Hanoi Hvis vi fortsetter lenge nok, får vi følgende utvikling: 1, 3, 7, 15, 31, 63, 127, 255, 511,… Dette ligner veldig mye på en ekspotensiell rekke, nemlig: 2 1 − 1, 2 2 − 1, 2 3 − 1,... Tilsynelatende blir det n-te tallet i denne utviklingen 2 n − 1. Følgelig: T(n) = 2 n − 1 =  (2 n )

33 Tilbakesubstitusjon Går fra T(n) mot T(1) Uttrykker en større instans med en mindre Akkumulerer alle resterende ledd til en matematisk rekke, og løser den

34 Tilbakesubstitusjon – Tower of Hanoi Vet at T(n) = 2T(n−1)+1, T(n−1) = 2T(n−2)+1, T(n − 2) = 2T(n − 3) + 1 osv T(n) = 2T(n − 1) + 1 T(n) = 2(2T(n − 2) + 1) + 1 T(n) = 2(2(2T(n − 3) + 1) + 1) + 1 osv

35 Tilbakesubstitusjon – Tower of Hanoi Hvis vi ganger ut, får vi T(n) = 2T(n − 1) + 1 T(n) = 4T(n − 2) T(n) = 8T(n − 3) osv

36 Tilbakesubstitusjon – Tower of Hanoi ”Gjetter” følgende løsning for T(n) som uttrykk av T(N-j): T(n) = 2 j T(n − j) + 2 j−1 + 2 j− Vi vet at T(1) = 1. La T(N-j) = T(1), altså j=n-1 T(n) = 2 n-1 T(1) + 2 n n− Siden T(1) = 1: T(n) = 2 n n n− = Rottman gir oss at T(n) = 2 n - 1 =  (2 n )

37 Variabelskifte Samme idé som variabelskifte for integralregning Vi erstatter en variabel med en annen som gir enklere rekurrensligning

38 Variabelskifte T(n) = 2T(n/2) + O(1), T(1) = 1 La n = 2 m for en eller annen m, slik at T(n)=T(2 m ): T(2 m ) = 2T(2 m-1 ) + 1, T(2 0 )=1 Definerer i tillegg S(m) = T(2 m ), S(m-1) = T(2 m-1 ) osv Får da: S(m) = 2S(m-1) +1, S(0) = 1

39 Variabelskifte Dette ligner veldig mye på ligningen vi hadde for Tower of Hanoi. Da vet vi også at S(m) =  (2 m ) Siden 2 m = n, er T(n) =  (n) Denne teknikken kan også benyttes på rekurrenser som inneholder kvadratrøtter osv.

40 Substitusjonsmetoden Gjett en løsning, og bruk induksjon til å vise at det stemmer Må være forsiktig og presis Egner seg best som gjette/bevismetode Krever mer forståelse og innsikt enn iterasjonsmetodene

41 Tremetoden Tegn et rekursjonstre for T(n) og nedover Hver node får verdien f(n) i en tilsvarende T(n) Deretter summeres alle noder for hele treet Som regel er det to tilfeller

42 Summen av alle f(n) for et nivå i treet er konstant Da kan vi bare gange denne verdien med høyden til treet Eksempel: T(n) = 2T(n/2) + n, T(1) = 1 Høyden til treet er lg(n). Summen på hvert nivå er n. Den totale summen er derfor n*lg(n)

43 Summen av alle f(n) for et nivå i treet er en funksjon av dybden til noden Setter opp en summasjon og løser den Eksempel: T(n) = 2T(n/2) + 1, T(1) = 1 Summen for et nivå med dybde i er 2 i Den totale summen er i så fall

44 Masterteoremet La T(n) være definert for ikke-negative heltall med rekurrensen T(n) = aT(n/b) + f(n) Da sier masterteoremet følgende: Hvis f(n) = for en ε > 0, T(n) = Hvis f(n) =, T(n) = Hvis f(n) = for en ε > 0 hvor af(n/b) ≤ cf(n) for en konstant c < 1for alle store n, T(n) = Hva betyr dette?

45 Øving 4 - Prinsessejakt Kjør et søk fra startnoden Husk hvilke noder du har funnet For alle andre noder: Tell antall kanter mellom disse Regn ut kanter/noder 2 Tweak: Alle søkene er i samme graf Husk på hvilke noder du kan nå fra tidligere søk. Da slipper du å gjøre like mange søk.

46 Øving 5 - Veibygging Ganske rett frem Oversett fra pseudokode i boka Både Prim og Kruskal fungerer Prim er lettest å implementere Tips for å klatre på lista: Regn på kjøretid for når de forskjellige algoritmene er best


Laste ned ppt "Alg. Dat Øvingsforelesning 5 Kompleksitetsanalyse Torbjørn Moralnd"

Liknende presentasjoner


Annonser fra Google