Løsningsforslag for Obligatorisk Oppgave 1 Algoritmer og Datastrukturer ITF20006 Lars Vidar Magnusson Frist 310114 Den første obligatoriske oppgaven tar for seg de fem første forelesningene, som i hovedsak har dreiet seg om hvordan man analyserer en algoritme Løsningsforslaget inneholder ikke analyse av faktisk kjøretid i den første og tredje oppgaven Dette ble gjort fordi poenget med disse var primært å la studentene få erfare forskjellen mellom faktisk kjøretid og asymptotisk kjøretid på egen hånd Praktisk Informasjon Det er med disse oppgavene dere skal få den nødvendige erfaringen dere trenger, så det kreves at alle innleveringer skal være individuelt arbeid Det er selvsagt til lov å hjelpe hverandre, men den endelige besvarelsen skal være et resultat av eget arbeid Besvarelser som viser tegn plagiering vil bli underkjente Dere kan selv velge hvilket språk dere vil implementere algoritmene i, men hvis dere skulle trenge hjelp kan det være greit å holde seg til enten Java, C# eller C (eller SML for spesielt interesserte) Både kode og tekst skal samles i en enkel rapport som så sendes til meg på larsvmagnusson@hiofno Rapporten skal være i pdf-format og skal være strukturert i henhold til oppgavene Dere står fritt i om koden legges direkte inn i besvarelsesteksten som figurer eller om dere legger den til som appendix og bruker refaranser Oppgave 1 Analyser kjøretiden til de følgende algoritmene gitt i pseudokode Det skal gjøres både en detaljert analyse, en asymptotisk analyse og en analyse av faktisk kjøretid For den detaljerte analysen kan dere anta at hver linje er tar én tidsenhet For den faktiske kjøretiden må pseudokoden implementeres og testes med forskjellige inputstørrelser I denne oppgaven er det viktigste at de klarer å komme frem til korrekt asymptotisk notasjon (det er greit om de blander O, Omega og Theta, så lenge alle er store) Detaljene i den detaljerte analysen er mindre viktig, men de bør ha fått med seg de grove trekkene 1
Oppgave1A(n) 1 sum = 0 2 for i = 1 to n 3 sum = sum + i 4 return sum Detaljert analyse: T (n) = 1 + (n + 1) + n + 1 = 2n + 3 Asymptotisk analyse: T (n) = 2n + 3 = Θ(n) Oppgave1B(n) 1 sum = 0 2 for i = 1 to n 3 for j = 1 to n 4 sum = sum + i 5 sum = sum + j 6 return sum Detaljert analyse: Asymptotisk analyse: T (n) = 1 + (n + 1) + n(n + 1) + n 2 + n 2 + 1 = 3n 2 + 2n + 3 T (n) = 3n 2 + 2n + 3 = Θ(n 2 ) Oppgave1C(n) 1 sum = 0 2 for i = 1 to n 3 sum = sum + i 4 for j = 1 to n 5 sum = sum + k 6 return sum Detaljert analyse: T (n) = 1 + (n + 1) + n + (n + 1) + n + 1 = 4n + 4 2
Asymptotisk analyse: T (n) = 4n + 4 = Θ(n) Oppgave1D(n) 1 sum = 0 2 for i = 1 to n 3 for j = 1 to n 4 for k = 1 to n 5 sum = sum + k 6 return sum Detaljert analyse: T (n) = 1 + (n + 1) + n(n + 1) + n 2 (n + 1) + n 3 + 1 Asymptotisk analyse: = 2n 3 + 2n 2 + 2n + 3 T (n) = 2n 3 + 2n 2 + 2n + 3 = Θ(n 3 ) Oppgave1E(n) 1 sum = 0 2 for i = 1 to n 3 for j = 1 to n 4 for k = 1 to n 5 sum = sum + i 6 sum = sum + j 7 sum = sum + k 8 return sum Detaljert analyse: T (n) = 1 + (n + 1) + n(n + 1) + n 2 (n + 1) + n 3 + n 3 + n 3 + 1 = 4n 3 + 2n 2 + 2n + 3 Asymptotisk analyse: T (n) = 4n 3 + 2n 2 + 2n + 3 = Θ(n 3 ) Oppgave1F(n) 1 sum = 0 2 i = 1 3 while i n 4 sum = sum + i 5 i = 2i 6 return sum 3
Detaljert analyse: T (n) = 1 + 1 + ( log 2 n + 2) + ( log 2 n + 1) + ( log 2 n + 1) + 1 = 3 log 2 n + 7 Asymptotisk analyse: T (n) = 3 log 2 n + 7 = Θ(log n) Oppgave1G(n) 1 sum = 0 2 i = 1 3 while i n 4 for j = 1 to n 5 sum = sum + j 6 i = 2i 7 return sum Detaljert analyse: T (n) = 1 + 1 + ( log 2 n + 2) + ( log 2 n + 1)(n + 1) + ( log 2 n + 1)n + ( log 2 n + 1) + 1 = 2n log 2 n + 2n + 3 log 2 n + 7 Asymptotisk analyse: T (n) = 2n log 2 n + 2n + 3 log 2 n + 7 = Θ(n log n) Oppgave 2 I denne oppgaven bør de i hovedsak ha alt likt fasiten, men de matematiske transformasjonene som blir brukt i substitusjonsmetoden kan selvsagt variere A Finn en gjetning for en asymptotisk øvre grense for recurrence ligningen under ved hjelp av rekursjonstrær Verifiser den asymptotiske grensen først med substitusjonsmetoden (matematisk induksjon) og så masterteoremet { Θ(1) if n = 1 T (n) = 3T (n/2) + Θ(n) if n > 1 Finner gjetning ved hjelp av et rekursjonstre Vi begynner med å sette inn cn for Θ(n) som intern kostnad i hver node i treet og ekspanderer til vi ser et mønster 4
cn c( n 2 ) c( n 2 ) c( n 2 ) T (1) T (1) T (1) T (1) T (1) T (1) T (1) T (1) T (1) T (1) T (1) T (1) Høyden h på treet blir: n 2 h = 1 2 h = n h = log 2 n Da har vi 3 h = 3 log 2 n = n log 2 3 antall barn med kostnad Θ(1) hver, som gir en total kostnad for barna på Θ(n log 2 3 ) Vi har kan nå sette sammen en ligning for kostnaden til recurrence-ligningen ved å summere kostnadene på alle nivåene i treet T (n) = cn + 3 2 cn + 9 4 cn + + Θ(nlog 2 3 ) = i=0 h 1 3 2 = Θ(n log 2 3 ) i cn + Θ(n log 2 3 ) Vår gjetning blir dermed O(n log 2 3 ) siden det bare blir spurt om en øvre grense Dette gjør også beviset enklere Beviset er gitt under med substitusjonsmetoden ie matematisk induksjon Vi gjetter på O(n log 2 3 ) Dette krever at T (n) cn log 2 3 Vi setter cn log 2 3 for T og kn for Θ(n) (vi setter inn konstanten k for å ikke blande med konstanten c) i recurrence ligningen og får T (n) = 3c( n 2 )log 2 3 + kn = 3c( nlog 2 3 2 log 2 3 ) + kn = cn log 2 3 + kn Dette fører ikke frem til den ønskede formen på T (n) cn log 2 3 cn log 2 3 + kn > cn log 2 3 så lenge k > 0 siden 5
Vi reduserer derfor gjetningen vår med en lavereordens ledd for å prøve å få matematikken til å gå opp Siden vi endte opp med et n-ledd til overs, er det naturlig å begynne med en gjetning som trekker fra et n-ledd ie O(n log 2 3 n) ( (n ) ) log2 3 n T (n) = 3c + kn 2 2 = cn log 2 3 3cn 2 + kn cn log 2 3 cn, så lenge c 2k Begrensingen c 2k kommer fra å løse ulikheten 3cn kn cn 2 3c 2 k c 3c 2 c k c 2 k c 2k For å fullføre beviset må vi se på grensetilfellet også Vi vet fra definisjonen av ligningen at T (1) = Θ(1) = O(1) = m, hvis vi setter konstanten i Θ(1) i basisleddet til en konstant m > 0 Siden dette ikke oppfyller kravet T (n) c(n log 2 3 n) så må vi se på større verdier av n T (2) = 3T (1) + kn = 3m + k Vi må så prøve bevise at dette oppfyller kravet T (n) c(n log 2 3 n) 3m + k c(2 log 2 3 2) = c(3 2) = c c(2 log 2 3 2), så lenge c 3m + k Vi har da bevist at T (n) = O(n log 2 3 ) lenge n 2 og c 3m + k med substitusjonsmetoden Vi kan verifisere dette beviset med masterteoremet Vi må da sammenligne n log b a med Θ(n) n log b a = n log 2 3 Vi ser enkelt n log 2 3 er polynomisk større enn Θ(n), så da får vi T (n) = Θ(n log 2 3 ) = O(n log 2 3 ) 6
B Hvilke metoder for å løse recurrence-ligninger er brukbare på ligningen under Begrunn svaret Bruk en av de applikable metodene for å komme frem til en øvre grense { Θ(1) if n = 1 T (n) = T (n 1) + Θ(n) if n > 1 Vi kan ikke bruke masterteoremet for å løse recurrence-ligningen siden den ikke er på formen T (n) = at (n/b) + f(n) Vi står da igjen med rekursjonstrær og substitusjonsmetoden Det er enkelt å se at siden n minkes med 1 på hvert nivå, så vil vi få rekursjonstreet få en høyde på n Jobben internt i hver node er Θ(n) = cn Selvom n minker for hvert nivå, er kostnaden avhengig av størrelsen n Vi kan derfor ganske enkelt multiplisere høyden med kostnaden og ende opp med en gjetning på n n = n 2 = O(n 2 ) Vi verifiserer så denne gjetningen med substitusjonsmetoden Vi vil bevise at T (n) = O(n 2 ) Dette krever at T (n) = cn 2 Vi bytter ut T (n) med cn 2 og Θ(n) med kn (for den interne kostnaden) T (n) = c(n 1) 2 + kn = cn 2 2cn + c + kn = cn 2 c(2n 1) + kn cn 2, så lenge n 1 og c 1 Begrensingen kommer fra å løse ulikheten c(2n 1) + kn 0 c(2n 1) kn c kn 2n 1 For grensetilfellet så prøver vi T (1) = 1 og c 1 2 = c Vi kan derfor si at n 0 = 1 og c = 1 og at vi har bevist at T (n) = O(n 2 ) Oppgave 3 I denne oppgaven skal dere implementere og analysere algoritmen Square- Matrix-Multiply-Recursive som vi gikk gjennom i forelesningen Her kreves det ideelt sett at de har kommet frem til en implementasjon som ligner (har de samme operasjonene i samme rekkefølge) på pseudokodeutgaven gitt under Det er i grunn nokså enkelt å konvertere pseudokoden til faktisk kode, men studentene har hatt en rekke problemer i forhold til hvordan man partisjonerer med indekser 7
Analysen bør være mest mulig lik med analysen gjort i fasiten (jeg har sagt at de kan utelate basistilfellet av det matematiske beviset) Square-Matrix-Multiply-Recursive(A, B) 1 n = Arows 2 let C be a new n n matrix 3 if n == 1 4 c 11 = a 11 b 11 5 else partition A, B, and C 6 C 11 = Square-Matrix-Multiply-Recursive(A 11, B 11 ) +Square-Matrix-Multiply-Recursive(A 12, B 21 ) 7 C 12 = Square-Matrix-Multiply-Recursive(A 11, B 12 ) +Square-Matrix-Multiply-Recursive(A 12, B 22 ) 8 C 21 = Square-Matrix-Multiply-Recursive(A 21, B 11 ) +Square-Matrix-Multiply-Recursive(A 22, B 21 ) 9 C 22 = Square-Matrix-Multiply-Recursive(A 21, B 12 ) +Square-Matrix-Multiply-Recursive(A 22, B 22 ) 10 return C Siden matrisene A og B er n n matriser kan de representeres med vanlige arrays på størrelse n 2 Koeffisienten c ij in matrise (0-indeksert) aksesseres da i arrayet a med a[in + j] Dere skal implementere to utgaver, en som kopierer delmatrisene inn i nye arrays, og en som bruker to indeks-variable for å angi hvilken del av matrisen det jobbes med Den første utgaven som kopierer inn i nye matriser er implementert i funksjonene under P a r t i s j o n e r e r en matrise m med ø s t r r e l s e n x n t i l f i r e nye d e l m a t r i s e r med ø s t r r e l s e n/2 x n /2 Det a l l o k e r e s n y t t minne f o r hver d e l m a t r i s e og i n n h o l d e t f r a f o r e l d e r matrisen k o p i e r e s inn public s t a t i c f l o a t [ ] [ ] p a r t i t i o n ( f l o a t [ ] m, int n ) { int partn = n / 2 ; // Den nye ø s t r r e l s e n f l o a t [ ] [ ] p a r t s = { // De nye d e l m a t r i s e n e new f l o a t [ partn partn ], new f l o a t [ partn partn ], new f l o a t [ partn partn ], new f l o a t [ partn partn ] ; Kopierer inn i n n h o l d e t f r a m inn i ø t i l h r e n d e d e l m a t r i s e for ( int p = 0 ; p < p a r t s l e n g t h ; p++) { int pi = p / 2 ; // 0 f o r ø f r s t e d e l r a d i m, 1 f o r andre int pj = p % 2 ; // 0 f o r ø f r s t e d e l k o l o n n e i m, 1 f o r andre for ( int i = 0 ; i < partn ; i ++) for ( int j = 0 ; j < partn ; j++) p a r t s [ p ] [ i partn + j ] = m[ ( pi partn + i ) n + ( pj partn + j ) ] ; 8
return p a r t s ; Adderer i n n h o l d e t i a og b og l e g g e r r e s u l t a t e t i c public s t a t i c f l o a t [ ] f l o a t [ ] a, f l o a t [ ] b, f l o a t [ ] c ) { for ( int i = 0 ; i < a l e n g t h ; i ++) c [ i ] = a [ i ] + b [ i ] ; return c ; S e t t e r sammen f i r e d e l m a t r i s e r t i l en matrise Den k o p i e r e r i n n h o l d e t f r a d e l m a t r i s e n e i pars inn i matrisen m public s t a t i c f l o a t [ ] u n P a r t i t i o n ( f l o a t [ ] [ ] parts, f l o a t [ ] m, int n ) { int partn = n / 2 ; Kopierer inn i n n h o l d e t f r a d e l m a t r i s e n e inn åp k o r r e k t p l a s s i m for ( int p = 0 ; p < p a r t s l e n g t h ; p++) { int pi = p / 2 ; // 0 f o r ø f r s t e d e l r a d i m, 1 f o r andre int pj = p % 2 ; // 0 f o r ø f r s t e d e l k o l o n n e i m, 1 f o r andre for ( int i = 0 ; i < partn ; i ++) for ( int j = 0 ; j < partn ; j++) m[ ( pi partn + i ) n + ( pj partn + j ) ] = p a r t s [ p ] [ i partn + j ] ; return m; Rekursiv m u l t i p l i k a s j o n s m e t o d e implementert d i r e k t e f r a pseudokoden g i t t i f o r e l e s n i n g og f a g b o k a Den e n e s t e f o r s k j e l l e n er at j e g har l a g t t i l ø s t r r e l s e n n som e t argument og k a l l e t t i l u n P a r t i t i o n f o r å s e t t c sammen public s t a t i c f l o a t [ ] m u l t i p l y ( f l o a t [ ] a, f l o a t [ ] b, int n ) { f l o a t [ ] c = new f l o a t [ n n ] ; i f ( n == 1) c [ 0 ] = a [ 0 ] b [ 0 ] ; else { int partn = n / 2 ; 9
f l o a t [ ] [ ] aparts = p a r t i t i o n ( a, n ) ; f l o a t [ ] [ ] bparts = p a r t i t i o n ( b, n ) ; f l o a t [ ] [ ] cparts = p a r t i t i o n ( c, n ) ; m u l t i p l y ( aparts [ 0 ], bparts [ 0 ], partn ), m u l t i p l y ( aparts [ 1 ], bparts [ 2 ], partn ), cparts [ 0 ] ) ; m u l t i p l y ( aparts [ 0 ], bparts [ 1 ], partn ), m u l t i p l y ( aparts [ 1 ], bparts [ 3 ], partn ), cparts [ 1 ] ) ; m u l t i p l y ( aparts [ 2 ], bparts [ 0 ], partn ), m u l t i p l y ( aparts [ 3 ], bparts [ 2 ], partn ), cparts [ 2 ] ) ; m u l t i p l y ( aparts [ 2 ], bparts [ 1 ], partn ), m u l t i p l y ( aparts [ 3 ], bparts [ 3 ], partn ), cparts [ 3 ] ) ; u n P a r t i t i o n ( cparts, c, n ) ; return c ; Den andre versjonen av algoritmen som bruker indekser for å angi en delmatrise er gitt i listingene under Denne har vært vanskelig for studentene å få til, så her har det kommet frem en rekke interessante variasjoner Denne k l a s s e n b r u k e s t i l å r e p r e s e n t e r e enten en matrise e l l e r en d e l m a t r i s e En nxn matrise a : i =0, j =0, n=n, mn=n, m=new f l o a t [ n n ] En t o p r i g h t d e l m a t r i s e av matrisen a : i =0, j =(a n /2), n=(a n /2), mn=a mn, m=a m private s t a t i c class SubMatrix { public int i, j, n, mn; // Startrad, // S t a r t k o l o n n e, // ø D e l m a t r i s e S t r r e l s e // ø M a t r i s e S t r r e l s e public f l o a t [ ] m; // Matrisen l a g r e t som en array public SubMatrix ( int i, int j, int n, f l o a t [ ] m, int mn) { this i = i ; this j = j ; this n = n ; this m = m; this mn = mn; 10
Tar en ( d e l ) matrise og d e l e r den opp i f i r e d e l e r Delene b l i r r e t u r n e r t i e t array i ø f l g e n d e ø r e k k e f l g e : t o p l e f t, t o p r i g h t, b o t t o m l e f t, b o t t o m r i g h t public s t a t i c SubMatrix [ ] p a r t i t i o n ( SubMatrix m) { int partn = m n / 2 ; SubMatrix [ ] p a r t s = { new SubMatrix (m i, m j, partn, mm, mmn), new SubMatrix (m i, partn + m j, partn, mm, mmn), new SubMatrix ( partn + m i, m j, partn, mm, mmn), new SubMatrix ( partn + m i, partn + m j, partn, mm, mmn) ; return p a r t s ; Adderer i n n h o l d e t i d e l m a t r i s e n e a og b og l e g g e r r e s u l t a t e t åp r i k t i g p l a s s i d e l m a t r i s e n c public s t a t i c SubMatrix SubMatrix a, SubMatrix b, SubMatrix c ) { for ( int i = 0 ; i < a n ; i ++) for ( int j = 0 ; j < a n ; j++) c m[ ( c i + i ) c mn + c j + j ] = a m[ ( a i + i ) a mn + a j + j ] + b m[ ( b i + i ) b mn + b j + j ] ; return c ; Rekursiv metode f o r m a t r i s e m u l t i p l i k a s j o n, implementert d i r e k t e e t t e r pseudokoden i boka Legg merke t i l at SubMatrix k l a s s e n b rukes åbde t i l å r e p r e s e n t e r e m a t r i s e r og d e l m a t r i s e r public s t a t i c SubMatrix m u l t i p l y ( SubMatrix a, SubMatrix b ) { SubMatrix c = new SubMatrix ( 0, 0, a n, new f l o a t [ a n a n ], a n ) ; i f ( c n == 1) c m[ c i c mn + c j ] = a m[ a i a mn + a j ] b m[ b i b mn + b j ] ; else { SubMatrix [ ] aparts = p a r t i t i o n ( a ) ; SubMatrix [ ] bparts = p a r t i t i o n ( b ) ; SubMatrix [ ] cparts = p a r t i t i o n ( c ) ; m u l t i p l y ( aparts [ 0 ], bparts [ 0 ] ), m u l t i p l y ( aparts [ 1 ], bparts [ 2 ] ), cparts [ 0 ] ) ; m u l t i p l y ( aparts [ 0 ], bparts [ 1 ] ), m u l t i p l y ( aparts [ 1 ], bparts [ 3 ] ), cparts [ 1 ] ) ; 11
m u l t i p l y ( aparts [ 2 ], bparts [ 0 ] ), m u l t i p l y ( aparts [ 3 ], bparts [ 2 ] ), cparts [ 2 ] ) ; m u l t i p l y ( aparts [ 2 ], bparts [ 1 ] ), m u l t i p l y ( aparts [ 3 ], bparts [ 3 ] ), cparts [ 3 ] ) ; return c ; Flere studenter har kommet fram til en alternativ algoritme som også fungerer ved å bruke indekser for å angi delmatriser Denne versjonen er lik den som bruker indekser over bortsett fra at den ikke bruker en metode for å addere Den akkumulerer i stedet i basistilfellet Veldig elegant i grunn, siden man da slipper å allokere en ny c i hvert rekursive kall Rekursiv metode f o r m a t r i s e m u l t i p l i k a s j o n som s k i l l e r seg f r a pseudokoden g i t t i boka F o r s k j e l l e n l i g g e r i hvordan adderingen b l i r ø u t f r t B a s i s t i l f e l l e t ( hvor n=1) t a r åhnd om adderingen i s t e d e t f o r at v i ø u t f r e r adderingen i en egen metoden Dette har f o r t r i n n e t at man s l i p p e r å a l l o k e r e en ny matrise f o r c åp h v e r t åniv, men d e t er v i k t i g å merke seg at denne a l g o r i t m e n i k k e l e n g e r den samme som b l i r b e s k r e v e t av pseudokoden ( selvom de ø l s e r d e t samme problemet ) public s t a t i c SubMatrix m u l t i p l y ( SubMatrix a, SubMatrix b, SubMatrix c ) { i f ( c n == 1) c m[ c i c mn + c j ] += a m[ a i a mn + a j ] b m[ b i b mn + b j ] ; else { SubMatrix [ ] aparts = p a r t i t i o n ( a ) ; SubMatrix [ ] bparts = p a r t i t i o n ( b ) ; SubMatrix [ ] cparts = p a r t i t i o n ( c ) ; m u l t i p l y ( aparts [ 0 ], bparts [ 0 ], cparts [ 0 ] ) ; m u l t i p l y ( aparts [ 1 ], bparts [ 2 ], cparts [ 0 ] ) ; m u l t i p l y ( aparts [ 0 ], bparts [ 1 ], cparts [ 1 ] ) ; m u l t i p l y ( aparts [ 1 ], bparts [ 3 ], cparts [ 1 ] ) ; m u l t i p l y ( aparts [ 2 ], bparts [ 0 ], cparts [ 2 ] ) ; m u l t i p l y ( aparts [ 3 ], bparts [ 2 ], cparts [ 2 ] ) ; m u l t i p l y ( aparts [ 2 ], bparts [ 1 ], cparts [ 3 ] ) ; m u l t i p l y ( aparts [ 3 ], bparts [ 3 ], cparts [ 3 ] ) ; return c ; Dere skal ressonere dere frem til en recurrence-ligning for begge utgavene, og forklare hvorfor samme ligning kan brukes til å beskrive begge to Dere skal så gjøre en analyse ved hjelp av rekursjonstrær slik at dere kommer frem til en gjetning for en funksjon som beskriver kjøretiden til algoritmen Denne skal 12
dere så verifisere både med substitusjonsmetoden (matematisk induksjon) og masterteoremet Vi holder oss først til de to tenkte versjonene av algoritmen (ikke den som noen studenter har kommet frem til selv) Her må de ha fått med seg at kopieringssteget i den første versjonen ikke endrer recurrenceligningen siden den er av samme orden (Θ(n 2 )) som adderingen Vi får bare 2Θ(n 2 ) som kan transformeres til Θ(n 2 ) Vi ender derfor opp med følgende recurrenceligning for de to første versjonene { Θ(1) if n = 1 T (n) = 8T (n/2) + Θ(n 2 ) if n > 1 Den alternative algoritmen av indeksversjonen hvor adderingen er flyttet til basistilfellet endrer derimot recurrenceligningen Så her faller faller kravet om samme recurrenceligning for både kopierings- og indeks-utgaven gjennom Her får vi følgende recurrenceligning for indeksversjonen { Θ(1) if n = 1 T (n) = 8T (n/2) + Θ(1) if n > 1 Et tenkt rekursjonstre for begge disse recurrenceligningene vil ha 8 forgreininger fra hver node Vi får derfor 8 h antall barn på det nederste nivået (n = 1) Høyden h på rekursjonstreet er kan finnes ved å løse ligningen n/2 h = 1 n 2 h = 1 2 h = n h = log 2 n Vi får derfor 8 log 2 n = n log 2 8 = n 3 antall bladnoder med Θ(1) kjøretid ie Θ(n 3 ) kjøretid for alle barna Kostnaden internt i hver node avhenger av leddet Θ(n 2 ) i recurrenceligningen På rotnivået får vi en kostnad på cn 2, på første nivå får vi (8/2)cn 2, på andre nivå får (8/2) 2 cn 2 osv Dette gir oss en sum log 2 n 1 i=0 cn 2 Dette leddet har lavere kostnad (lavere orden) enn Θ(n 3 ) som er kostnaden for kjøringen av alle basistilfellene Vi har derfor kommet frem til at kjøretiden til algoritmen må være Θ(n 3 ) Dette gjelder også for den alternative algoritmen som noen studenter har kommet frem til, siden den eneste forskjellen fra resonnementet over er at summen for kostnadene internt i nodene bare blir log 2 n 1 i=0 cn Vi beviser at denne gjetningen er korrekt ved å bruke substitusjonsmetoden Vi må derfor bevise at T (n) cn 3 for en konstant c > 0 Vi setter inn gjetningen i recurrenceligningen og transformerer for å bevise det rekursive tilfellet 13
T (n) = 8c(n/2) 3 + kn 2 = cn 3 + kn 2 Dette vil ikke lede frem til ønsket form (T (n) cn 3 ) siden kn 2 leddet lager problemer Vi modifiserer derfor gjetningen ved å trekke fra et lavere ordens ledd Den nye gjetningen er T (n) = O(n 3 n 2 ) og vi må bevise at T (n) c(n 3 n 2 ) T (n) = 8c ( (n/2) 3 (n/2) 2) + kn 2 = cn 3 2cn 2 + kn 2 cn 3 cn 2, så lenge c k Da gjenstår bare basistilfellet T (1) = Θ(1) = 1 c(1 3 1 2 ) = 0 ie T (1) > c(1 3 1 2 ) som ikke oppfyller kravet Vi prøver derfor med n = 2 T (2) = 8T (1) + k2 2 = 8m + 4k Vi får c(2 3 2 2 ) = 4c for vår gjetning Vi vet da at T (n) cn 3 så lenge c 2m + k hvor k og m er konstantleddene for henholdsvis den interne- og basis-kostnaden Vi har da bevist at kjøretiden til algoritmen er Θ(n 3 ) med substitusjonsmetoden Vi skal også verifisere dette beviset med masterteoremet Vi må da sammenligne n log b a med Θ(n 2 ) n log b a = n log 2 8 = n 3 Siden n 3 er polynomisk større enn Θ(n 2 ) så har vi verifisert kjøretiden for algoritmen Θ(n 3 ) med masterteoremet Selv om kopieringsutgaven har en høyere kostnad enn indeksutgaven har begge utgaver samme asymptotisk notasjon Det skiller bare en konstant mellom de to utgavene når vi analyserer kjøretiden Er dette også tilfellet i praksis? Test de to utgavene av algoritmen med forskjellige inputstørrelser og bedøm om det bare skiller en konstant mellom de eller ikke Diskuter resultatet og legg vekt på å forklare hvorfor det eventuelt ikke stemmer at det bare skiller en konstant 14