Lösning av några vanliga rekurrensekvationer

Relevanta dokument
Sökning och sortering

Datastrukturer. föreläsning 3. Stacks 1

Algoritmanalys. Inledning. Informationsteknologi Malin Källén, Tom Smedsaas 1 september 2016

Programkonstruktion och Datastrukturer

Föreläsning 5 Innehåll

Rekursion och induktion för algoritmkonstruktion

Föreläsning 7 Innehåll. Rekursion. Rekursiv problemlösning. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursion. Rekursivt tänkande:

Föreläsning 5 Innehåll. Val av algoritm och datastruktur. Analys av algoritmer. Tidsåtgång och problemets storlek

Föreläsning 11 Datastrukturer (DAT037)

Tentamen med lösningsförslag Datastrukturer för D2 DAT 035

Föreläsning 13 Datastrukturer (DAT037)

DAI2 (TIDAL) + I2 (TKIEK)

Tentamen Datastrukturer D DAT 035/INN960

TDDI16 Datastrukturer och algoritmer. Algoritmanalys

SCB :-0. Uno Holmer, Chalmers, höger 2 Ex. Induktiv definition av lista. // Basfall

Programmering för språkteknologer II, HT2014. Rum

FÖRELÄSNING 2, TDDC74, VT2018 BEGREPP PROBLEMLÖSNING MED HJÄLP AV FALLANALYS PROBLEMLÖSNING MED HJÄLP AV REKURSION

Föreläsning 13 Datastrukturer (DAT037)

Linjärt minne. Sammanhängande minne är ej flexibelt. Effektivt

TENTAMEN: Algoritmer och datastrukturer. Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad.

Rekursion. Koffman & Wolfgang kapitel 5

Föreläsning 4 Datastrukturer (DAT037)

Lösningsförslag till tentamen Datastrukturer, DAT037 (DAT036), Tiden det tar att utföra en iteration av loopen är oberoende av värdet på

Algoritmer, datastrukturer och komplexitet

Tommy Färnqvist, IDA, Linköpings universitet

Exempel: Förel Rekursion III Nr 14. Uno Holmer, Chalmers,

Rekursion och induktion för algoritmkonstruktion

Föreläsning 13. Rekursion

Datastrukturer och algoritmer. Föreläsning 15 Inför tentamen

Datastrukturer och algoritmer. Föreläsning 4 Test, Stack och Kö

Föreläsning 5: Kardinalitet. Funktioners tillväxt

Föreläsning 6 Innehåll. Rekursion. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursiv problemlösning. Rekursion. Rekursivt tänkande:

Tentamen Datastrukturer D DAT 036/INN960

Tentamen Datastrukturer för D2 DAT 035

TENTAMEN: Algoritmer och datastrukturer. Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad.

Introduktion till algoritmer - Lektion 4 Matematikgymnasiet, Läsåret Lektion 4

Algoritmer och effektivitet. Föreläsning 5 Innehåll. Analys av algoritmer. Analys av algoritmer Tidskomplexitet. Algoritmer och effektivitet

Vad har vi pratat om i kursen?

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 5 Jonas Lindgren, Institutionen för Datavetenskap, LiU

TENTAMEN: Algoritmer och datastrukturer. Läs detta!

Algoritmer och datastrukturer TDA143

Tentamen Datastrukturer D DAT 036/INN960

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 6 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Föreläsning 2 Datastrukturer (DAT037)

Föreläsning 5 Datastrukturer (DAT037)

Metodanrop - primitiva typer. Föreläsning 4. Metodanrop - referenstyper. Metodanrop - primitiva typer

Algoritmanalys. Genomsnittligen behövs n/2 jämförelser vilket är proportionellt mot n, vi säger att vi har en O(n) algoritm.

TENTAMEN: Algoritmer och datastrukturer. Läs detta!

Tommy Färnqvist, IDA, Linköpings universitet. 2 Rekursion i C Implementation av rekursion Svansrekursion En till övning...

TENTAMEN: Algoritmer och datastrukturer. Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad.

Föreläsning 4 Datastrukturer (DAT037)

Rekursion och induktion för algoritmkonstruktion

Tommy Färnqvist, IDA, Linköpings universitet

Asymptotisk komplexitetsanalys

Datastrukturer och algoritmer

Sortering. Brute-force. Sortering Ordna element enligt relation mellan nyckelvärden

Föreläsning 11 Innehåll

Magnus Nielsen, IDA, Linköpings universitet

Föreläsning 2 Datastrukturer (DAT037)

Algoritmer och datastrukturer TDA Fredrik Johansson

Föreläsning 1 Datastrukturer (DAT037)

Översikt. Stegvis förfining. Stegvis förfining. Dekomposition. Algoritmer. Metod för att skapa ett program från ett analyserat problem

Datastrukturer och algoritmer

Tentamen Datastrukturer D DAT 035/INN960 (med mycket kortfattade lösningsförslag)

Hitta k största bland n element. Föreläsning 13 Innehåll. Histogramproblemet

Lösningsförslag till tentamen Datastrukturer, DAT037,

Algoritmer, datastrukturer och komplexitet

Datastrukturer D. Föreläsning 2

Pseudokod Analys av algoritmer Rekursiva algoritmer

Lösningsförslag till tentamen Datastrukturer, DAT037,

Föreläsning 1. Introduktion. Vad är en algoritm?

Föreläsning Datastrukturer (DAT037)

TENTAMEN: Algoritmer och datastrukturer. Läs detta!

Algoritmer, datastrukturer och komplexitet

BEGREPP HITTILLS FÖRELÄSNING 2 SAMMANSATTA UTTRYCK - SCHEME DATORSPRÅK

Några svar till TDDC70/91 Datastrukturer och algoritmer

Föreläsning 12 Innehåll

Tentamen Datastrukturer D DAT 035/INN960

Föreläsning 9. Sortering

Fredag 10 juni 2016 kl 8 12

Datastrukturer, algoritmer och programkonstruktion (DVA104, VT 2015) Föreläsning 6

Grundläggande datalogi - Övning 3

Upplägg. Binära träd. Träd. Binära träd. Binära träd. Antal löv på ett träd. Binära träd (9) Binära sökträd (10.1)

Tentamen i Algoritmer & Datastrukturer i Java

Lösningsförslag för tentamen i Datastrukturer (DAT036) från

Föreläsning 4. Kö Implementerad med array Implementerad med länkad lista Djup kontra bredd Bredden först mha kö

Teoretisk del. Facit Tentamen TDDC (6)

Kapitel 7: Analys av sorteringsalgoritmer

public static void mystery(int n) { if (n > 0){ mystery(n-1); System.out.print(n * 4); mystery(n-1); } }

Datastrukturer. föreläsning 2

ADS : STACK ADT: STACK. Stack och Kö -Implementering - Tilllämpningar. Oftast förekommande metoder i Stack. TopOfStack

Procedurer och villkor. Rekursiva procedurer. Exempel: n-fakultet

Procedurer och villkor

EDAA01 Programmeringsteknik - fördjupningskurs

Föreläsning 13 Innehåll

Föreläsning Datastrukturer (DAT037)

Föreläsning Datastrukturer (DAT036)

Föreläsning 11 Innehåll. Sortering. Sortering i Java. Sortering i Java Comparable. Sortering. O(n 2 )-algoritmer: urvalssortering insättningssortering

Föreläsning 9 Innehåll. Söndra och härska. Fibonaccitalen. Söndra och härska. Divide and conquer teknik för att konstruera rekursiva algoritmer.

Transkript:

1 (8) Lösning av några vanliga rekurrensekvationer Rekursiv beräkning av X n En rekursiv funktion som beräknar x n genom upprepad multiplikation, baserat på potenslagarna X 0 = 1 X n+1 = X X n float pow(float x,int n) { if ( n == 0 ) return 1.0; else return x*pow(x,n-1); Låt T(n) vara antalet multiplikationer som utförs då pow(x,n) anropas. Vi får de två rekurrensekvationerna: T(0) = 0 (1) T(n) = T(n-1) + 1 (2) Motivering: T(0) = 0 eftersom ingen multiplikation utförs då pow(x,0) anropas. I else-grenen utförs en multiplikation plus antalet multiplikationer som utförs av anropet pow(x,n-1), dvs 1 + T(n-1) multiplikationer. Rekurrensekvationen löses genom att utveckla (2) genom successiv substitution: Av (2) följer att T(n-1) = T(n-2) + 1 T(n-2) = T(n-3) + 1 T(n-3) = T(n-4) + 1 o.s.v. Högerledet i ekvation (2) kan då skrivas om med successiv substituition: T(n) = [T(n-2) + 1] + 1 substitution av T(n-2) + 1 för T(n-1) i (2) = T(n-2) + 2 förenkling = [T(n-3) + 1] + 2 substitution = T(n-3) + 3 förenkling = [T(n-4) + 1] + 3 substitution = T(n-4) + 4 förenkling Om proceduren upprepas når vi till slut T(n) = T(n-n) + n = T(0) + n = 0 + n enligt (1) = n T(n) = T(n-1) + 1 T(n-2) + 1 T(n-3) + 1 T(n-4) + 1...

Vi kan alltså dra slutsatsen att T(n) = O(n) 2 (8) Följande rekursiva funktion för beräkning av x n baseras på potenslagarna X 0 = 1 X 2n = X n X n X 2n+1 = X X n X n float pow2(float x,int n) { if ( n == 0 ) return 1.0; else if ( n % 2 == 0 ) return pow2(x,n/2)*pow2(x,n/2); else return x*pow2(x,n/2)*pow2(x,n/2); Vi får rekurrensekvationerna: T(0) = 0 (1) T(1) = 2 (2) T(n) = 2T(n/2) + c (c 2) (3) Motivering: I det ena rekursionsfallet sker en multiplikation, men två i det andra, alltså högst två multiplikationer, därav konstanten c. T(n) = 2[2T(n/4) + c] + c substitution = 4T(n/4) + 3c förenkling = 4[2T(n/8) + c] + 3c substitution = 8T(n/8) + 7c förenkling = 8[2T(n/16) + c] + 7c substitution = 16T(n/16) + 15c förenkling Vi ser ett tydligt mönster av tvåpotenser och i det allmänna fallet har högerledet formen 2 k T(n/2 k ) + (2 k -1) c Genom att betrakta de (oändligt många) n som är tvåpotenser hoppas vi kunna reducera bort T-termen. Antag därför att n = 2 k, då får vi T(n) = n T(n/n) + (n-1) c = n 2 + (n-1) c enligt (2) Vi ser att T(n) = O(n) även i detta fall. Man kan säga att försöket att dela problemet i hälften så stora delproblem misslyckades eftersom varje delproblem löses två gånger. Rekursiva funktioner bör inte utföra redundant arbete.

En D&C-algoritm för X n 3 (8) En effektivare Divide & Conquer-algoritm beräknar x n utan upprepning av redan gjorda beräkningar: float dcpow(float x,int n) { if ( n == 0 ) return 1.0; else { float p = dcpow(x,n/2); if ( n % 2 == 0 ) return p*p; else return x*p*p; Vi får rekurrensekvationerna: T(0) = 0 (1) T(1) = 2 (2) T(n) = T(n/2) + c (c 2) (3) T(n) = [T(n/4) + c] + c substitution = T(n/4) + 2c förenkling = [T(n/8) + c] + 2c substitution = T(n/8) + 3c förenkling = [T(n/16) + c] + 3c substitution = T(n/16) + 4c förenkling Vi ser åter ett tydligt mönster av tvåpotenser och i det allmänna fallet har högerledet formen Antag att n = 2 k, då får vi (eftersom k = 2 log n): T(n) = T(n/n) + ( 2 log n) c = 2 + ( 2 log n) c enligt (2) Alltså är T(n) = O(log n). T(n/2 k ) + k c Anm. Denna analys är i princip även tillämplig för binärsökning.

Hanois torn 4 (8) Funktionen move finns i OH från den första föreläsningen om rekursion. void move(char A,char B,char C,int n) { if ( n > 0 ) { move(a,c,b,n-1); System.out.println(A + --> + B); move(c,b,a,n-1); Låt T(n) vara antalet utskrifter som utförs då move(x,y,z,n) anropas. Vi får rekurensekvationerna: T(0) = 0 (1) T(n) = 2T(n-1) + 1 (2) T(n) = 2[2T(n-2) + 1] + 1 substitution = 4T(n-2) + 3 förenkling = 4[2T(n-3) + 1] + 3 substitution = 8T(n-3) + 7 förenkling = 8[2T(n-4) + 1] + 7 substitution = 16T(n-4) + 15 förenkling I det allmänna fallet har högerledet formen Antag att n = k, då får vi: T(n) = 2 n T(n - n) + (2 n -1) = 2 n 0 + (2 n -1) enligt (1) 2 k T(n - k) + (2 k -1) Vi kan dra slutsatsen att T(n) = O(2 n ) så move har exponentiell tidskomplexitet. Anm. Även induktionsbeviset sist i OH visar att T(n) = 2 n - 1.

Största delsegmentsumman i ett heltalsfält 5 (8) Den rekursiva Divide & Conquer-algoritmen för beräkning av största delsegmentsumman i ett heltalsfält som finns i kursboken har komplexiteten O(n log n). Låt T(n) vara antalet jämförelser som utförs då maxsumrec anropas med ett heltalsfält med n element. Rekurensekvationerna för algoritmen är: T(1) = 1 (1) T(n) = 2T(n/2) + n (2) Motivering: Det sker två rekursiva anrop för hälften så långa fältsegment. Termen n kommer från det faktum att de två looparna analyserar O(n) fältelement där n är längden hos det aktuella segmentet. T(n) = 2[2T(n/4) + n/2] + n substitution = 4T(n/4) + 2n förenkling = 4[2T(n/8) + n/4] + 2n substitution = 8T(n/8) + 3n förenkling = 8[2T(n/16) + n/8] + 3n substitution = 16T(n/16) + 4n förenkling I det allmänna fallet har högerledet formen Antag att n = 2 k, då får vi (eftersom k = 2 log n): 2 k T(n/2 k ) + k n T(n) = n T(n/n) + ( 2 log n) n = n 1 + ( 2 log n) n enligt (1) och vi kan därför dra slutsatsen att T(n) = O(n log n). Anm. Denna analys är i princip också tillämplig för sorteringsalgoritmerna merge sort och quicksort.

Kostnadsamortering vid fältdubblering 6 (8) Vid fältbaserade implementeringar av t.ex. stackar, FIFO-köer, prioritetsköer och hashtabeller används fältdubblering för att kunna amortera tidsåtgången för kopiering av elementen från ett fullt fält till ett tomt större fält. T.ex. ger denna teknik stackoperationen push komplexiteten O(1) i genomsnitt, kopiering inräknat. Vi skall nu visa att kopieringskostnaden för n push-operationer är O(n) då fältdubblering används. Låt T(n) vara den ackumulerade kopieringskostnaden för att sätta in n element i en stack. Antag att vi har en stack med n/2 element och att fältet är fullt. Den ackumulerade kostnaden för tidigare kopieringar av dessa n/2 element är då T(n/2). Elementen skall nu kopieras till ett tomt fält med n platser. Om kostnaden för kopiering per fältelement är C 1 så kostar kopieringen av n/2 element C 1 n/2. När kopieringen är klar kan vi sätta in n/2 element med push utan att någon kopiering behöver ske. Intuitivt kan man inse att för varje element som kopieras från det gamla fältet till det nya, så kan ett annat element senare sättas in med push i den lediga halvan utan att någon kopiering behöver ske. Figuren nedan beskriver situationen: T(n/2) n/2 kopiering C 1 n/2 Om vi sätter T(1) = C 0 och C = C 1 /2 så får vi rekurrensekvationerna: T(1) = C 0 (1) T(n) = T(n/2) + C n (2) T(n) = [T(n/4) + C n/2] + C n substitution = T(n/4) + 3/2 C n förenkling = [T(n/8) + C n/4] + 3/2 C n substitution = T(n/8) + 7/4 C n förenkling = [T(n/16) + n/8] + 7/4 C n substitution = T(n/16) + 15/8 C n förenkling I det allmänna fallet har högerledet formen Antag att n = 2 k, då får vi n/2 push utan kopiering T(n/2 k ) + ((2 k - 1) / (2 k-1 )) C n T(n) = T(n/n) + ((n-1)/(n/2)) C n = C 0 + (n-1) 2 C enligt (1) forts

7 (8) Uppenbarligen är T(n) = O(n), d.v.s. den totala kostnaden för kopiering av element vid insättning av n element med push växer linjärt med antalet insatta element. Således har push i genomsnitt komplexiteten O(1). Statisk fältutvidgning Som en jämförelse kan vi analysera komplexiteten för fältbaserad lagring då fältstorleken ökas med ett konstant antal nya platser C. Låt som förut T(n) vara den ackumulerade kopieringskostnaden för att sätta in n element i en stack. Antag att vi har en stack med n - C element och att fältet är fullt. Den ackumulerade kopieringskostnaden för dessa element är T(n - C). Elementen skall nu kopieras till ett tomt fält med n platser. Om kopieringskostnaden per fältelement är C 1 så kostar kopieringen av n - C element C 1 (n - C). När kopieringen är klar kan vi sätta in C element med push utan att någon kopiering behöver ske. För enkelhets skull antar vi att den initiala fältlängden är C, då kommer fältlängden alltid att vara en multipel av C. T(n - C) n - C kopiering C 1 (n - C) C push utan kopiering Om vi sätter T(1) = C 0 får vi rekurrensekvationerna: T(0) = C 0 (1) T(n) = T(n - C) + C 1 (n C) (2) T(n) = [T(n - 2C) + C 1 (n 2C)] + C 1 (n C) substitution = T(n - 2C) + C 1 ((n 2C) + (n C)) förenkling = [T(n - 3C) + C 1 (n 3C)] + C 1 ((n 2C) + (n C)) substitution = T(n - 3C) + C 1 ((n 3C) + (n 2C) + (n C)) förenkling = [T(n - 4C) + C 1 (n 4C)] + C 1 ((n 3C) + (n 2C) + (n C)) substitution = T(n - 4C) + C 1 ((n 4C) + (n 3C) + (n 2C) + (n C)) förenkling = T(n - kc) + C 1 ((n kc) + + (n 3C) + (n 2C) + (n C)) Antag att k = n/c, då får vi T(n) = T(0) + C 1 (0 + C + 2C + 3C + + (n C)) = C 0 + C 1 C = C 0 + C 1 C n/c termer Således är T(n) = O(n 2 ) så den genomsnittliga tidskomplexiteten per push är med denna metod O(n).

8 (8) Intuitivt kan man inse att ju större fältet blir, desto mindre andel av helheten utgörs av lediga celler efter varje omallokering, och desto större andel består av element som måste kopieras. Om vi sätter konstanten C till 1 måste faktiskt n element kopieras före varje push-operation. När vi betraktar asymptotisk komplexitet är värdet på C oväsentligt. När antalet element växer mot oändligheten kommer kopieringsarbetet att dominera beräkningstiden, oavsett värdet på C. Slutsatsen blir att detta sätt att hantera fält inte bör användas, utan den först nämnda metoden vilken i genomsnitt ger konstant tidsåtgång per push-operation.