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

Relevanta dokument
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 9 Innehåll. Söndra och härska. Fibonaccitalen. Söndra och härska. Divide and conquer teknik för att konstruera rekursiva algoritmer.

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.

Föreläsning 8 Innehåll

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

Rekursion och induktion för algoritmkonstruktion

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

Rekursion. Koffman & Wolfgang kapitel 5

Föreläsning 13. Rekursion

Föreläsning 11 Innehåll

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

Objektorienterad programmering E. Back to Basics. En annan version av printtable. Ett enkelt exempel. Föreläsning 10

Begreppet subtyp/supertyp i Java. Mera om generik. Generik och arv. Generik och arv. Innehåll

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

6 Rekursion. 6.1 Rekursionens fyra principer. 6.2 Några vanliga användningsområden för rekursion. Problem löses genom:

Föreläsning 3-4 Innehåll. Diskutera. Metod. Programexempel med metod

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

Föreläsning 3-4 Innehåll

Föreläsning 9 Innehåll

Rekursion och induktion för algoritmkonstruktion

Rekursion och induktion för algoritmkonstruktion

Algoritmer och datastrukturer H I HÅKAN S T R Ö M B E R G N I C K L A S B R A N D E F E L T

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

Föreläsning 5 Innehåll

Föreläsning 4 Innehåll. Abstrakta datatypen lista. Implementering av listor. Abstrakt datatypen lista. Abstrakt datatyp

Sortering. Föreläsning 12 Innehåll. Sortering i Java. Sortering i Java Exempel. Sortering

Föreläsning 12 Innehåll

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

Datastrukturer D. Föreläsning 2

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)

Föreläsning 10 Innehåll. Prioritetsköer och heapar. ADT Prioritetskö. Interface för Prioritetskö. Exempel på vad du ska kunna

Föreläsning 2 Datastrukturer (DAT037)

Föreläsning 12 Innehåll

Föreläsning REPETITION & EXTENTA

DAT043 - föreläsning 8

Föreläsning 5. Rekursion

Tentamen i Algoritmer & Datastrukturer i Java

Föreläsning 4 Innehåll

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

Rekursion. Att tänka rekursivt Att programmera rekursivt i Java Exempel. Programmeringsmetodik -Java 254

Datastrukturer. föreläsning 2

Datastrukturer i kursen. Föreläsning 8 Innehåll. Träd rekursiv definition. Träd

Föreläsning ALGORITMER: SÖKNING, REGISTRERING, SORTERING

Objektorienterad programmering E. Algoritmer. Telefonboken, påminnelse (och litet tillägg), 1. Telefonboken, påminnelse (och litet tillägg), 2

Dugga Datastrukturer (DAT036)

Abstrakt datatyp. -Algoritmer och Datastrukturer- För utveckling av verksamhet, produkter och livskvalitet.

ADT Prioritetskö. Föreläsning 12 Innehåll. Prioritetskö. Interface för Prioritetskö. Prioritetsköer och heapar

Lösningsförslag till tentamen Datastrukturer, DAT037,

Algoritmer. Två gränssnitt

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

Föreläsning 10 Innehåll. Diskutera. Inordertraversering av binära sökträd. Binära sökträd Definition

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

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

Tommy Färnqvist, IDA, Linköpings universitet

Grundläggande datalogi - Övning 3

Sökning och sortering

Tentamen, Algoritmer och datastrukturer

Introduktion till programmering D0009E. Föreläsning 5: Fruktbara funktioner

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

ADT Kö. Seminarium 4 Köer och Stackar Innehåll. Operationer. ADT Stack. Definition. Definition

Föreläsning 10 Innehåll

TDDI16 Datastrukturer och algoritmer. Algoritmanalys

Föreläsning Datastrukturer (DAT037)

Föreläsning 11 Innehåll. Diskutera. Binära sökträd Definition. Inordertraversering av binära sökträd

Klassen BST som definierar binära sökträd med tal som nycklar och enda data. Varje nyckel är unik dvs förekommer endast en

Tentamen Datastrukturer (DAT037)

F9 - Polymorfism. ID1004 Objektorienterad programmering Fredrik Kilander

Föreläsning 11: Rekursion

Magnus Nielsen, IDA, Linköpings universitet

Algoritmer, datastrukturer och komplexitet

Tentamen Datastrukturer (DAT036)

Programmeringsteknik - fördjupningskurs

Algoritmer, datastrukturer och komplexitet

if (n==null) { return null; } else { return new Node(n.data, copy(n.next));

Lite om felhantering och Exceptions Mer om variabler och parametrar Fält (eng array) och klassen ArrayList.

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

Introduktion till programmering SMD180. Föreläsning 5: Fruktbara funktioner

Medan ni väntar. 2. Skriv metoden. 3. Skriv metoden. Naturligtvis rekursivt och utan användning av Javas standardmetoder.

TENTAMEN PROGRAMMERINGSMETODIK MOMENT 2 - JAVA, 4P

F11 - Rekursion. ID1004 Objektorienterad programmering Fredrik Kilander

Föreläsning 1: Dekomposition, giriga algoritmer och dynamisk programmering

Programmering för Språkteknologer II. Innehåll. Associativa datastrukturer. Associativa datastrukturer. Binär sökning.

Seminarium 13 Innehåll

Objektorienterad programmering

Föreläsning 1, vecka 7: Rekursion

Dagens program. Programmeringsteknik och Matlab. Objektorienterad programmering. Vad är vitsen med att ha både metoder och data i objekten?

Tentamen Datastrukturer, DAT037 (DAT036)

Övningshäfte 2: Induktion och rekursion

String [] argv. Dagens Agenda. Mer om arrayer. Mer om arrayer forts. String [] argv. argv är variabelnamnet. Arrayer och Strängar fortsättning

Föreläsning 5. Rekursion

Föreläsning 4 Datastrukturer (DAT037)

Föreläsning 2 Datastrukturer (DAT037)

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Dekomposition och dynamisk programmering

Föreläsning 9-10 Innehåll

Lösning av några vanliga rekurrensekvationer

Att deklarera och att använda variabler. Föreläsning 10. Synlighetsregler (2) Synlighetsregler (1)

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

Datastrukturer. föreläsning 3. Stacks 1

Transkript:

Föreläsning 6 Innehåll Rekursion Begreppet rekursion Rekursiv problemlösning Samband mellan rekursion och induktion Söndra-och-härska-algoritmer Dynamisk programmering Undervisningsmoment: föreläsning 6, övningsuppgifter 7, lab 3 Avsnitt i läroboken: 5.1-5.5 I gamla upplagan: 7.1-7.5 PFK (Föreläsning 6) HT 2016 1 / 48 Rekursion Rekursivt tänkande: Hur många år fyller du? Ett år mer än förra året! Rekursiv problemlösning: Dela upp problemet i en eller flera enklare versioner av det ursprungliga problemet. Rekursiva metoder är metoder som anropar sig själva (för mindre värden på storleksparameter). Många datastrukturer går att definiera rekursivt. Ex: listor, träd PFK (Föreläsning 6) HT 2016 2 / 48 Rekursiv problemlösning Rekursiv problemlösning Mönster för rekursiv algoritm Kan liknas vid önsketänkande: Om jag har lösningen till en (eller flera) mindre instans(er) så kan jag konstruera en lösning för den aktuella instansen genom att... Ex: Summera de n första talen i en vektor. Rekursivt tänkande: Om summan av de n-1 första talen är känd, så får vi lösningen genom att summera denna summa och det sista talet. För att det ska fungera krävs basfall där lösningen ges explicit. Basfallen är (oftast) små instanser, t ex 0. I exemplet ovan är ett naturligt basfall n=0. Då är summan 0. Rekursiv lösning för problem med storlek n: Om problemet går att lösa för aktuellt n-värde: Lös det annars Lös problemet (rekursivt) för en eller flera mindre värden på n Kombinera dessa lösningar till en lösning på problemet för n PFK (Föreläsning 6) HT 2016 3 / 48 PFK (Föreläsning 6) HT 2016 4 / 48

Rekursiv beräkning av n! Exekvering och metodanrop Definition 0! =1 (basfall) n! =n (n 1)!, n heltal > 0 (rekursiva steget) För alla metodanrop (rekursiva såväl som icke-rekursiva) gäller: Ett anrop av en metod innebär att exekveringen fortsätter med den första satsen i den anropade metoden. När den anropade metoden är klar återupptas exekveringen i den metod där anropet gjordes. public static long factorial(int n) { if (n == 0) { return 1; else { return n * factorial(n - 1); public void p() { q(); public void q() { r(); public void r() { PFK (Föreläsning 6) HT 2016 5 / 48 PFK (Föreläsning 6) HT 2016 6 / 48 Exekvering av rekursiva metoder Exempel Exekvering och metodanrop 6 factorial(3) n = 3 return 3 * factorial(2) Vid exekvering av ett metodanrop skapar runtimesystemet en aktiveringspost. 2 factorial(2) n = 2 return 2 * factorial(1) 1 factorial(1) n = 1 return 1 * factorial(0) 1 factorial(0) n = 0 return 1 I aktiveringsposten finns uppgifter om återhoppsadress (där anropet gjordes) parametrarnas värden lokala variabler och deras värden Aktiveringsposterna placeras i en stack. Den metod som exekverar har sin post överst på stacken. Aktiveringsposten tas bort när metoden exekverat klart. PFK (Föreläsning 6) HT 2016 7 / 48 PFK (Föreläsning 6) HT 2016 8 / 48

Exekvering av rekursiva metoder Rekursiva metoder anropar sig själva. Det kommer att på stacken finnas aktiveringsposter för alla oavslutade upplagor av metoden. Stackens utseende under exekvering av ett anrop av factorial(3): Endast parmeterns värde visas för varje upplaga. n = 3 Efter anrop factorial(3) n = 2 n = 3 Efter anrop factorial(2) n = 1 n = 2 n = 3 Efter anrop factorial(1) n = 0 n = 1 n = 2 n = 3 Efter anrop factorial(0) n = 1 n = 2 n = 3 Efter return 1 n = 2 n = 3 n = 3 Efter return 1*factorial(0) Efter return 2*factorial(1) Efter return 3*factorial(2) Rekursiv metod En rekursiv metod måste ha: En eller flera parametrar som bestämmer problemets storlek Ett eller flera basfall som löses direkt. Ett eller flera rekursiva anrop. De rekursiva anropen måste leda till att ett basfall så småningom nås. public static int factorial(int n) { if (n == 0) { return 1; basfall else { return n * factorial(n - 1); rekursivt anrop parameter PFK (Föreläsning 6) HT 2016 9 / 48 PFK (Föreläsning 6) HT 2016 10 / 48 Övning Exempel: Skriv ut ett tal baklänges Algoritm Skriv en rekursiv metod som beräknar x n. n är ett positivt heltal. Definition x 0 = 1 x n = x x n 1, n heltal > 0 Problem: Givet ett heltal n 0. Skriv ut siffrorna i omvänd ordning. Exempel: Talet 257 ska ge utskriften 752 Basfall: Talet har bara en siffra. Skriv ut denna enda siffra. Rekursiva steget: Skriv först ur sista siffran. Skriv därefter ut de övriga siffrorna i omvänd ordning. PFK (Föreläsning 6) HT 2016 11 / 48 PFK (Föreläsning 6) HT 2016 12 / 48

Exempel: Skriv ut ett tal baklänges Rekursiv metod Exempel: Skriv ut ett tal baklänges Negativa tal public static void reverse(int n) { if (n < 10) { System.out.print(n); else { System.out.print(n % 10); reverse(n / 10); Metoden klarar inte och ska inte klara negativa tal Det bör kontrolleras. Vi inför därför en metod som först kontrollerar parametern och därefter anropar den rekursiva metoden: public static void printreverse(int n) { if (n < 0) { throw new IllegalArgumentException("Argument < 0"); reverse(n); System.out.println(); Den rekursiva metoden bör nu göras privat. PFK (Föreläsning 6) HT 2016 13 / 48 PFK (Föreläsning 6) HT 2016 14 / 48 Rekursion och listor Rekursiva datastrukturer Rekursion och listor Klassen SingleLinkedList från tidigare föreläsning Begreppet lista med n element kan definieras rekursivt: om n == 0 är listan tom (basfall) annars består den av ett första element följt av en lista med n 1 element public class SingleLinkedList<E> { private ListNode<E> first; private static class ListNode<E> { E element; ListNode<E> next; första elementet lista med n-1 element first next element next element next element null PFK (Föreläsning 6) HT 2016 15 / 48 PFK (Föreläsning 6) HT 2016 16 / 48

Diskutera Rekursion och listor Rekursion och listor Exempel Antag att vi vill skriva ut innehållet i listan i omvänd ordning med rekursiv teknik. Börja med att tänka ut basfall. enklare delproblem (rekursiva steget). Skissa sedan på algoritmen i pseudokod. Problem: Skriv ut innehållet i listan i omvänd ordning. public void printreverse() { printreverse(first); private void printreverse(listnode<e> node) { if (node!= null) { printreverse(node.next); System.out.println(node.element); PFK (Föreläsning 6) HT 2016 17 / 48 PFK (Föreläsning 6) HT 2016 18 / 48 Rekursion och listor Observationer Basfallet i printreverse syns inte. Basfallet är den tomma listan (node == null) dåingentinggörs. Metoden har tidskomplexitet O(n) det görs n metodanrop och i varje upplaga görs ett arbete som tar konstant tid. En icke-rekursiv variant är besvärligare att uttrycka. Ett alternativ är att söka efter sista, näst sista o.s.v. Det blir krångligare kod och högre tidskomplexitet. Ett annat alternativ är att använda en stack. Lika effektivt som den rekursiva lösningen, men något krångligare att uttrycka. I printreverse vi utnyttjat att vi har tillgång till den interna datastrukturen. Om man använder någon av Collection-klasserna i Java får man lösa det på något annat sätt. Man kan t.ex. skicka med en iterator som parameter till den rekursiva metoden. PFK (Föreläsning 6) HT 2016 19 / 48 Hanois torn 1 2 3 4 5 pinne 1 pinne 2 pinne 3 n skivor finns i avtagande storlek på en pinne (start, t ex 1). Flytta dem så att de kommer i samma inbördes ordning på en av de andra pinnarna (dest, t ex 3). Även den tredje pinnen (temp, t ex 2) får utnyttjas för mellanlagring. PFK (Föreläsning 6) HT 2016 20 / 48

Hanois torn regler Bara en skiva i taget får flyttas. En skiva som tas från en pinne måste genast läggas på en av de andra pinnarna. Det får aldrig inträffa under flyttningarnas gång att en större skiva hamnar ovanför en mindre (på samma pinne). Hanois torn rekursiv lösning Basfall: Endast en skiva att flytta (n = 1). Flytta skivan från start till dest. Rekursiva steget: 1 Flytta först de n 1 översta skivorna från start till temp. 2 Flytta därefter den största skivan från start till dest. 3 Till sist flyttas de n 1 skivorna från temp till dest. 1 2 3 4 5 1. från start till temp 3. från temp till dest 2. från start till dest PFK (Föreläsning 6) HT 2016 21 / 48 PFK (Föreläsning 6) HT 2016 22 / 48 Hanois torn rekursiv metod Binärsökning Algoritm public void move(int n, int start, int dest, int temp) { if (n == 1) { System.out.println("Move from " + start + " to " + dest); else { move(n - 1, start, temp, dest); System.out.println("Move from " + start + " to " + dest); move(n - 1, temp, dest, start); Om en vektor är sorterad i växande ordning och vi söker ett element x, finns en effektiv algoritm: Basfall: 0 element. Sökt element finns ej. Rekursiva steget: 1 Jämför x med mittelementet i vektorn. Om likhet, avbryt. 2 Om x är mindre än mittelementet, fortsätt sökningen i vänster halva av vektorn. 3 Om x är större än mittelementet, fortsätt sökningen i höger halva av vektorn. PFK (Föreläsning 6) HT 2016 23 / 48 PFK (Föreläsning 6) HT 2016 24 / 48

Binärsökning - parametrar I den rekursiva lösningen måste varje upplaga av metoden känna till vilken del av vektorn den arbetar med. Det kommer därför att behövas parametrar för första index och sista index i den rekursiva metoden. Användare ska dock inte behöva anropa med två index. Det räcker att de anger vad som söks och vilken vektor det ska sökas i. Den publika metoden som användare får tillgång till: /** Returns the index of x if found in the array a, otherwise -1. The array must be sorted.*/ public static int binarysearch(int[] a, int x) { return binarysearch(a, x, 0, a.length - 1); Den rekursiva hjälpmetodens rubrik: private static int binarysearch(int[] a, int x, int first, int last); PFK (Föreläsning 6) HT 2016 25 / 48 Binärsökning Generiska metoder Den publika metoden som användare får tillgång till: /** Returns the index of x if found in the array a, otherwise -1. The array must be sorted.*/ public static <E extends Comparable<E>> int binarysearch(e[] a, E x) { return binarysearch(a, x, 0, a.length - 1); Den rekursiva hjälpmetodens rubrik: private static <E extends Comparable<E>> int binarysearch(e[] a, E x, int first, int last); Implementering följer, men först en liten utvikning om generiska metoder. Binärsökning - generisk metod Vi vill ha en generell metod, d.v.s. en metod som kan söka efter ett element i en vektor av godtycklig typ (och inte bara heltal). Lösning: Låt metoden vara generisk, dvs deklarera en typparameter (E) i metodrubriken. public static <E> int binarysearch(e[] a, E x) Vi måste dock kräva att elementen är av en typ för vilka jämförelse är definierad eftersom vektorn ska vara sorterad. Lösning: Kräv att den klass som ersätter E implementerar interfacet Comparable. public static <E extends Comparable<E>> int PFK (Föreläsning 6) HT 2016 26 / 48 Generiska metoder Man kan deklarera generiska metoder, genom att parametrisera metoden med en eller flera typparametrar. Exempel: public class Utilities { /* Fyller alla platser i a med elementet x */ public static <T> void fill(t[] a, T x) { for (int i = 0; i < a.length; i++) { a[i] = x; Typparameter (en eller flera) anges inom < och > före metodens returtyp. PFK (Föreläsning 6) HT 2016 27 / 48 PFK (Föreläsning 6) HT 2016 28 / 48

Generiska metoder Den generiska metoden binarysearch Generiska metoder kan anropas utan att man explicit anger vad typen T är: Integer[] nbrs = new Integer[10]; Utilities.fill(nbrs, -1); String[] a = new String[5]; Utilities.fill(a, "abc"); För det första anropet fastställer kompilatorn typen T till Integer och idetandratillstring. public static <E extends Comparable<E>> int binarysearch(e[] a, E x) { return binarysearch(a, x, 0, a.length - 1); Har en typparameter E med inskränkning: E måste vid anrop vara en klass som implementerar interfacet Comparable<E> Har returtyp int: Returtypen skrivs efter typparametrarna Har två parametrar som använder E i sin deklaration: E[] a och E x PFK (Föreläsning 6) HT 2016 29 / 48 PFK (Föreläsning 6) HT 2016 30 / 48 Binärsökning Privat metod Binärsökning Effektivitet private static <E extends Comparable<E>> int binarysearch(e[] a, E x, int first, int last) { if (first > last) { return -1; else { int mid = first + ((last - first) / 2); int compresult = x.compareto(a[mid]); if (compresult == 0) { return mid; else if (compresult < 0) { return binarysearch(a, x, first, mid - 1); else { return binarysearch(a, x, mid + 1, last); Linjärsökning är O(n) i värsta fall. Binärsökningen är mycket effektivare. I värsta fall finns inte x i vektorn. Vi börjar med vektorstorlek n, därefter n/2, n/4,n/2 k,,1, 0. Det krävs 2 log(n) halveringar i värsta fall. I varje upplaga krävs konstant arbete. Hela algoritmen blir därför O(logn) i värsta fall. PFK (Föreläsning 6) HT 2016 31 / 48 PFK (Föreläsning 6) HT 2016 32 / 48

Samband mellan rekursion och induktion Exempel Visa att 1 + 2 + 3 + + n = n(n + 1)/2 förallan 1 Matematisk induktion används ofta för att bevisa samband som gäller för positiva heltal n. Bevisen görs i två steg: 1 Visa att sambandet gäller för ett eller flera små värden på n. 2 Visa att om man gör antagandet att sambandet håller för alla heltal n upp till ett visst värde k, så gäller det även för närmast större värde k+1. 1 n = 1. Vänsterledet = 1. Högerledet = 1 2/2 = 1. Stämmer. 2 Vi antar nu att 1 + 2 + + n = n(n + 1)/2 för1apple n apple k (*) Visa att 1 + 2 + + k + k + 1 =(k + 1)(k + 2)/2. Vänsterledet = (1 + 2 + + k)+k + 1 = [enligt (*)] = k(k + 1)/2 + k + 1 =(k 2 + 3k + 2)/2 Högerledet = (k + 1)(k + 2)/2 =(k 2 + 3k + 2)/2 = Vänsterledet. PFK (Föreläsning 6) HT 2016 33 / 48 PFK (Föreläsning 6) HT 2016 34 / 48 Induktion för att visa att en rekursiv algoritm är korrekt public static long factorial(int n) { if (n == 0) { return 1; else { return n * factorial(n - 1); 1 När n=0 blir resultatet 1 vilket är korrekt enligt def av n! 2 Antag att algoritmen ger korrekt resultat för 0 apple n apple k. (*) Anrop factorial(k+1) ger (eftersom k + 1 > 0) resultatet (k + 1) factorial(k+1-1) =(k + 1) factorial(k). Enligt induktionsantagandet (*) ger anropet factorial(k) korrekt resultat, dvs k!. Vi får därför resultatet (k + 1) k! =(k + 1)! V.S.B. Söndra och härska Divide and conquer teknik för att konstruera rekursiva algoritmer. Avser rekursiva algoritmer som gör minst två rekursiva anrop i varje upplaga. Problemet delas upp i två eller flera mindre som löses rekursivt (söndra). Lösningarna kombineras till en lösning till det ursprungliga problemet (härska). 2 87 34 12 56 10 2 34 87 10 12 56 2 10 12 34 56 87 PFK (Föreläsning 6) HT 2016 35 / 48 PFK (Föreläsning 6) HT 2016 36 / 48

Söndra och härska Fibonaccitalen Sortering av element i en vektor: Dela vektorn i två lika stora halvor Sortera (rekursivt) första halvan a[0... n/2] Sortera (rekursivt) andra halvan a[n/2+1... n-1] Slå samman de båda sorterade delvektorerna så att hela vektorn a[0... n-1] blir sorterad Det är i härska-steget som själva algoritmkonstruktionen ligger. Söndra-stegen är bara rekursiva anrop. Sorteringsmetoden, Mergesort, blir mycket snabb när steg 3 utförs på ett effektivt sätt. Vi återkommer till denna metod senare i kursen. Leonardo Pisano Fibonacci Born: 1170 in (probably) Pisa (now in Italy) Died: 1250 in (possibly) Pisa (now in Italy) Acertainmanputapairofrabbitsinaplacesurroundedon all sides by a wall. How many pairs of rabbits can be produced from that pair in a year if it is supposed that every month each pair begets a new pair which from the second month on becomes productive? PFK (Föreläsning 6) HT 2016 37 / 48 PFK (Föreläsning 6) HT 2016 38 / 48 Fibonaccitalen söndra och härska Definition F n = F n 1 + F n 2 för n 2 F 0 = 0 F 1 = 1 public static long fib(int n) { if (n <= 1) { return n; else { return fib(n - 1) + fib(n - 2); Diskutera Fibonaccitalen public static long fib(int n) { if (n <= 1) { return n; else { return fib(n - 1) + fib(n - 2); Är detta en bra metod? Hur många anrop av metoden fib krävs för att beräkna andra fibonaccitalet? Tredje? Fjärde? PFK (Föreläsning 6) HT 2016 39 / 48 PFK (Föreläsning 6) HT 2016 40 / 48

Fibonaccitalen effektivitet Samma Fibonaccital kommer att beräknas många gånger. Ineffektivt! Det blir exponentiell tidskomplexitet, dvs O(2 n ) för att beräkna fib(n). Studera t ex ett anrop fib(4): fib(3) fib(4) fib(2) Dynamisk programmering Dynamisk programmering innebär att man i en tabell håller reda på vilka instanser av problemet man redan löst. När man behöver lösningen till en viss instans kontrollerar man först i tabellen om den redan beräknats. I så fall hämtas lösningen där, d.v.s. man gör inget rekursivt anrop. Om lösningen inte finns i tabellen gör man ett rekursivt anrop och sätter sedan in den beräknade lösningen i tabellen. fib(2) fib(1) fib(1) fib(0) 0 1 1 2-1 -1-1 -1-1 fib(1) fib(0) 0 1 2 3 4 5 6 7 PFK (Föreläsning 6) HT 2016 41 / 48 PFK (Föreläsning 6) HT 2016 42 / 48 Dynamisk programmering - Fibonaccitalen public long fib(int n) { long[] table = new long[n+1]; // skapa en tabell for (int i = 0; i <= n; i++) { table[i] = -1; // negativt värde <=> ej beräknat return recfib(table, n); private long recfib(long[] table, int n) { if (table[n] < 0 ) { if (n <= 1) { table[n] = n; else { table[n] = recfib(table, n-1) + recfib(table, n-2); return table[n]; Dynamisk programmering - Fibonaccitalen Dynamisk programmering för Fibonaccitalen har linjär tidskomplexitet. Varje tal beräknas en gång. fib(4) fib(3) fib(2) fib(1) fib(0) PFK (Föreläsning 6) HT 2016 43 / 48 PFK (Föreläsning 6) HT 2016 44 / 48

Fibonaccitalen iterativ lösning Effektiviteten vid beräkning av Fibonaccitalen med hjälp av dynamisk programmering är av samma storleksordning som iden iterativa algoritmen, d.v.s. linjär: public long fib(int n) { if (n <= 1) { return n; else { int nbr1 = 0; int nbr2 = 1; int res = 0; for (int i = 2; i <= n; i++) { res = nbr1 + nbr2; nbr1 = nbr2; nbr2 = res; return res; PFK (Föreläsning 6) HT 2016 45 / 48 När ska rekursion användas? Vissa av de exempel vi sett kan lika enkelt lösas icke-rekursivt. Ex. beräkning av n! Ibland leder rekursion till väldigt ineffektiva algoritmer. Ex. fibonaccitalen Rekursion bör användas då Det är svårt att uttrycka lösningen icke-rekursivt. Gäller t.ex. algoritmer som manipulerar datastrukturer som träd och grafer. Det finns icke-rekursiv lösning, men den rekursiva är effektivare. Ex: sortering Det finns icke-rekursiv lösning och en lika effektiv rekursiv lösning som är enklare (att förstå, implementera... ). Ex: binärsökning, behandla elementen i en lista i omvänd ordning PFK (Föreläsning 6) HT 2016 46 / 48 Rekursion Datorlaboration 3 Fraktaler Rita fraktala figurer med hjälp av rekursion. Exempel på vad du ska kunna Förklara begreppet rekursion. Förklara hur rekursion fungerar. Formulera rekursiva algoritmer och implementera rekursiva metoder. Förklara begreppet söndra-och-härska i samband med rekursion. Använda dynamisk programmering för att eliminera onödiga rekursiva anrop. Kochs triangel byggs upp av tre linjer, där varje linje (längd, riktning) ersätts med fyra nya linjer: Berg byggs upp av en triangel (tre punkter) som ersätts av fyra nya trianglar: b b a c a c PFK (Föreläsning 6) HT 2016 47 / 48 PFK (Föreläsning 6) HT 2016 48 / 48