Rekursion: varför Problem delas upp i mindre bitar algoritm för att lösa problemet erhålls från problemformuleringen Exempel på problem som kan lösas med rekursion: Beräkningar, t.ex. upphöjt, Fibonacci-tal, faktorisering, fakultet Sökproblem, t.ex. schack Tornet i Hanoi De flesta svårare problem Många svåra problem får elegant lösning med rekursion
Upphöjt Rekursion innebär att en metod anropar sig själv Exempel: beräkna upphöjt-funktionen, a b Vi använder: a 0 = 1 a b = a a b 1 Problemet delas därmed upp i två mindre: Delproblem 1: beräkna a b 1 Delproblem 2: multiplicera med a
Upphöjt Exempel: beräkna upphöjt-funktionen, a b Vi använder: a b = a a b 1 a 0 = 1 public static int upphojt(int a, int b) { if (b == 0) return 1; else return a * upphojt(a, b - 1); } Rekursion
Primtalsfaktorisering Problem: Givet ett positivt heltal n, Primtalsfaktorisera n Varje primtalsfaktor > 1 ska anges så många gånger som n kan delas med faktorn Exempelkörning: Mata in ett tal: 60 Faktorer: 2 2 3 5
Primtalsfaktorisering Idé: Om n inte har någon mindre primtalsfaktor, skriv ut n Om n har någon primtalsfaktor f, skriv ut f och primtalsfaktorisera n / f
Primtalsfaktorisering Idé: Om n inte har någon mindre primtalsfaktor, skriv ut n Om n har någon primtalsfaktor f, skriv ut f och primtalsfaktorisera n / f Denna lösning är rekursiv Delproblem 1: hitta en primtalsfaktor Delproblem 2: primtalsfaktorisera ett mindre tal Rekursion
Primtalsfaktorisering Idé: Om n inte har någon mindre primtalsfaktor, skriv ut n Om n har någon primtalsfaktor f, skriv ut f och primtalsfaktorisera n / f Denna lösning är rekursiv Delproblem 1: hitta en primtalsfaktor Delproblem 2: primtalsfaktorisera ett mindre tal Delproblem 1: För varje k från 2 till n, testa om k delar n: if ((n % k) == 0) Rekursion
Primtalsfaktorisering class PrimtalsFaktorisering { private static int hittafaktor(int n) { for (int k = 2; k < n; k++) if ((n % k) == 0) return k; return n; } } public static void faktorisera(int n) { if (n > 1) int faktor = hittafaktor(n); Std.out.println(faktor); faktorisera(n / faktor); } }
Tornen i Hanoi Utgångsläge: 3 pinnar 64 guldskivor av olika storlekar på pinne 1 Storleksordning, den största underst Mål: Få över alla skivor till pinne 3
Tornen i Hanoi Regler för att flytta skivor: Den översta skivan på valfri pinne får flyttas till annan valfri pinne MEN: Ingen skiva får någonsin ligga på en mindre skiva
Tornen i Hanoi Om vi bara har 2 skivor:
Tornen i Hanoi Om vi har 3 skivor:
Tornen i Hanoi Om vi har n skivor: rekursiv lösning n 1 skivor
Tornen i Hanoi Rekursiv lösning För att flytta ett torn av n skivor från a till c, med b som hjälppinne (1) Flytta n 1 skivor från a till b; c är hjälppinne (2) Flytta 1 skiva från a till c (3) Flytta n 1 skivor från b till c; a är hjälppinne (1) (2) (3) 2 mindre delproblem rekursion
Tornen i Hanoi Rekursiv lösning class Hanoi { public static void flytta(int antal, int fran, int hjalp, int till) { if (antal > 0) { flytta(antal - 1, fran, till, hjalp); Std.out.println(fran + " -> " + till); flytta(antal - 1, hjalp, fran, till); } } } public static void main(string[] args) { Std.out.println("Antal brickor:"); int antal = Std.in.readInt(); flytta(antal, 1, 2, 3); }
Tornen i Hanoi Tillbaka till Hanoi: hur lång tid tar det T(n) = antal förflyttningar som behövs för att få n brickor från en pinne till en annan T(1) = 1 (för att få 1 bricka från en pinne till en annan, behövs bara 1 förflyttning) T(n) = T(n 1) + T(1) + T(n 1) (för att flytta n brickor, gör vi tre saker: flyttar n 1 brickor, flyttar 1 bricka, och flyttar n 1 brickor igen) Har lösning T(n) = 2 n 1
Tornen i Hanoi Tillbaka till Hanoi: hur lång tid tar det T(64) = 2 64 1 = 18 446 744 073 709 551 615 Om munkarna flyttar en skiva i sekunden, tar det 5.8 miljarder sekel att flytta alla skivorna ca 45 gånger längre tid än universums ålder (13 miljarer år enl. NASA:s Wilkinson Microwave Anisotropy Probe (WMAP) projekt)
Ett sätt att lösa problem Dela upp problemet i mindre delproblem Lös delproblemen, var för sig Kombinera lösningarna till en lösning för det ursprungliga problemet
Ett sätt att lösa problem Dela upp problemet i mindre delproblem Lös delproblemen, var för sig Med rekursion Kombinera lösningarna till en lösning för det ursprungliga problemet Om delproblemen är av samma typ men mindre