Rekursjon. (Big Java kapittel 13) Fra Urban dictionary: recursion see recursion. IN1010 uke 8 våren Dag Langmyhr

Like dokumenter
Rekursjon. (Big Java kapittel 13) Fra Urban dictionary: recursion see recursion. IN1010 uke 8 våren Dag Langmyhr

Rekursiv programmering

Rekursjon som programmeringsteknikk

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

Sortering med tråder - Quicksort

En implementasjon av binærtre. Dagens tema. Klassestruktur hovedstruktur abstract class BTnode {}

UNIVERSITETET I OSLO

I et Java-program må programmøren lage og starte hver tråd som programmet bruker. Er dette korrekt? Velg ett alternativ

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

Jentetreff INF1000 Debugging i Java

"behrozm" Oppsummering - programskisse for traversering av en graf (dybde først) Forelesning i INF februar 2009

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

Oppsummering. Kort gjennomgang av klasser etc ved å løse halvparten av eksamen Klasser. Datastrukturer. Interface Subklasser Klasseparametre

IN1010. Fra Python til Java. En introduksjon til programmeringsspråkenes verden Dag Langmyhr

alternativer til sortering og søking binære trær søketrær Ikke-rekursiv algoritme som løser Hanois tårn med n plater

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

UNIVERSITETET I OSLO

Rekursiv programmering

Løsnings forslag i java In115, Våren 1998

Oppgave 1. Oppgave 2. Oppgave 3. Prøveeksamen i INF1000. Ole Christian og Arne. 23. november 2004

INF1010 Rekursive metoder, binære søketrær. Algoritmer: Mer om rekursive kall mellom objekter Ny datastruktur: binært tre

Rekursjon. Hanois tårn. Milepeler for å løse problemet

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

Rekursjon. Binærsøk. Hanois tårn.

Kapittel 8: Programutvikling

PG4200 Algoritmer og datastrukturer Forelesning 3 Rekursjon Estimering

Dagens temaer. Sortering: 4 metoder Søking: binærsøk Rekursjon: Hanois tårn

Java-kurs. Andreas Knudsen Nils Grimsmo 9th October 2003

Oppgave 1. INF1000 Uke 13. Oppgave 2. Oppgave 3. Er dette lovlige deklarasjoner (når de foretas inni en metode)? JA NEI

INF1010. grensesni-et Comparable<T> grensesni-et Iterable<T> rekursjon

INF1010. Sekvensgenerering Alle mulige sekvenser av lengde tre av tallene 0, 1 og 2: Sekvensgenerering. Generalisering. n n n! INF1010 INF1010 INF1010

En algoritme for permutasjonsgenerering

Fra Python til Java. En introduksjon til programmeringsspråkenes verden. Dag Langmyhr

UNIVERSITETET I OSLO

INF1010. Rekursjon En rekursiv definisjon av rekursjon, slik det kunne stå i en ordbok: Introduksjon til Rekursiv programmering

Oversikt. INF1000 Uke 1 time 2. Repetisjon - Introduksjon. Repetisjon - Program

IN1010. Fra Python til Java. En introduksjon til programmeringsspråkenes verden Dag Langmyhr

INF1010 Binære søketrær ++

Oppsummering del 2. Læringsmål Viktigste Java-elementer Eksamen Til sist. Læringsmål Hovedpunkter Tilbakemelding Eksamen. IN1010 uke 17 våren 2019

GUI («Graphical User Interface») del 2

Algoritmer og Datastrukturer

Prøveeksamen i INF1000. Ole Christian og Arne. 23. november 2004

Fra Python til Java, del 2

UNIVERSITETET I OSLO

Dagens tema. Hva er kompilering? Anta at vi lager dette lille programmet doble.rusc (kalt kildekoden): Hva er kompilering?

INF 1000 høsten 2011 Uke september

INF1010 Sortering. Marit Nybakken 1. mars 2004

Forkurs INF1010. Dag 1. Andreas Færøvig Olsen Tuva Kristine Thoresen

INF1010 Rekursjon. Marit Nybakken 1. mars 2004

INF1000 undervisningen INF 1000 høsten 2011 Uke september

Programmeringsspråket C

INF1000 oppgaver til uke 38 (17 sep 23 sep)

Binære trær: Noen algoritmer og anvendelser

Programmeringsspråket C

GUI («Graphical User Interface») del 2

Kort om meg. INF1000 Uke 2. Oversikt. Repetisjon - Introduksjon

UNIVERSITETET I OSLO

MAT-INF 1100: Obligatorisk oppgave 1

Programmeringsspråket C

Algoritmer og datastrukturer Løsningsforslag

Forelesning inf Java 4

UNIVERSITETET I OSLO

EKSAMEN. Dato: 18. mai 2017 Eksamenstid: 09:00 13:00

i=0 Repetisjon: arrayer Forelesning inf Java 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker 0*0 0*2 0*3 0*1 0*4

Mer objektorientert programmering

Feilmeldinger, brukerinput og kontrollflyt

Løsningsforslag ukeoppg. 6: 28. sep - 4. okt (INF Høst 2011)

TDT4100 Objektorientert programmering

Backtracking som løsningsmetode

Hva er verdien til variabelen j etter at følgende kode er utført? int i, j; i = 5; j = 10; while ( i < j ) { i = i + 2; j = j - 1; }

INF1000 (Uke 5) Mer om løkker, arrayer og metoder

Stack. En enkel, lineær datastruktur

MAT-INF 1100: Obligatorisk oppgave 1

INF1010 våren 2019 Onsdag 30. januar. Mer om unntak i Java (med litt repetisjon av I/O først)

INF2440 Uke 10, v2014 : Arne Maus OMS, Inst. for informatikk

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

INF1000 : Forelesning 4

INF1000: Forelesning 11. Oppgave 2. Oppgave 1. Husk å melde deg på prøveeksamen i INF1000! Ole Christian Lingjærde 7.november 2006

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

INF1000: Forelesning 7

De neste ukene. INF1000 Uke 12. Prøveeksamen. Nå - Prøveeksamen. Forelesning om IT og samfunn neste uke (13/11).

Java PRP brukermanual

Introduksjon til objektorientert. programmering. Hva skjedde ~1967? Lokale (og globale) helter. Grunnkurs i objektorientert.

i=0 i=1 Repetisjon: nesting av løkker INF1000 : Forelesning 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker j=0 j=1 j=2 j=3 j=4

Mattespill Nybegynner Python PDF

UNIVERSITETET I OSLO

Oversikt. INF1000 Uke 2. Repetisjon - Program. Repetisjon - Introduksjon

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

public static <returtype> navn_til_prosedyre(<parameter liste>) { // implementasjon av prosedyren

Kapittel 12: Rekursjon

UNIVERSITETET I OSLO

Transkript:

Fakultet Bredde Rekursjon Fibonacci Sjakk Hanois tårn Lister Oppsummering Rekursjon (Big Java kapittel 13) Fra Urban dictionary: recursion see recursion.

n! = n x n-1 x n-2 x... x 2 x 1 Å beregne fakultet Den matematiske funksjonen n fakultet (med notasjonen n!) er definert slik: 1! = 1 = 1 2! = 1 2 = 2 3! = 1 2 3 = 6 4! = 1 2 3 4 = 24 n! = 1 2 n =

En løsning med løkke Beregning av fakultet med løkke Fakultet1.java class Fakultet1 { static long fak(int k) { long res = 1; for (int i = 1; i <= k; i++) res = res * i; return res; public static void main(string[] arg) { int n = Integer.parseInt(arg[0]); for (int i = 1; i <= n; i++) System.out.println(i + "! = " + fak(i)); $ java Fakultet1 6 1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720

En rekursiv løsning En rekursiv løsning Vi kan imidlertid skrive denne metoden på en helt annen måte om vi innser at fakultetsfunksjonen kan defineres slik: 1!=1 n!=n (n 1)!

En rekursiv løsning Fakultet2.java class Fakultet2 { static long fak(int k) { if (k == 1) return 1; else return k * fak(k-1); public static void main(string[] arg) { int n = Integer.parseInt(arg[0]); for (int i = 1; i <= n; i++) System.out.println(i + "! = " + fak(i)); $ java Fakultet2 6 1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720

Hvor mange posisjoner trenger man til et gitt heltall? Bredden av et heltall Problem: Hvor mange posisjoner trenger man når man skal skrive ut et gitt heltall? $ java Bredde 3 3 har bredde 1 $ java Bredde -355-355 har bredde 4 class Bredde { static int w(int n) { if (n < 0) return 1 + w(-n); if (n <= 9) return 1; return 1 + w(n/10); public static void main(string[] arg) { int v = Integer.parseInt(arg[0]); System.out.println(v + " har bredde " + w(v));

Hvorfor er rekursjon en god idé? Rekursjon Programkode som kaller seg selv, kalles rekursiv kode. Noen problemer er rekursive av natur (for eksempel en kompilator eller Hanois tårn) Rekursiv programmering er spesielt nyttig for programmer som skal søke ulike veier til en mulig løsning (for eksempel en labyrint eller sjakkspill) Noen programmerere foretrekker rekursive løsninger.

Går det virkelig bra å skrive rekusiv kode? main main main main...fak(n)......fak(n)......fak(n)......fak(n)... fak fak fak Navn: k Navn: k Navn: k 3 3 3 Type: int if (k == 1) return 1; else return k * fak(k-1); Type: int if (k == 1) return 1; else return k * fak(k-1); Type: int if (k == 1) return 1; else return k * fak(k-1); fak fak Navn: k Navn: k 2 2 Type: int if (k == 1) return 1; else return k * fak(k-1); Type: int if (k == 1) return 1; else return k * fak(k-1); fak Navn: k 1 Type: int if (k == 1) return 1; else return k * fak(k-1); class Fakultet2 class Fakultet2 class Fakultet2 class Fakultet2 Tilstand 1 Tilstand 2 Tilstand 3 Tilstand 4

Hvorfor er Fibonacci-tallene interessante Fibonacci-tallene Tallsekvensen 1, 1, 2, 3, 5, 8, 13, 21, 34, 55,... der hvert tall er summen av de to foregående, forekommer usedvanlig ofte i naturen.

Hvorfor er Fibonacci-tallene interessante Leonardo Fibonacci (ca 1170 ca 1250) fant denne tallsekvensen som svar på hvordan kaniner formerer seg:

Hvorfor er Fibonacci-tallene interessante Overraskende ofte finner vi disse tallene i naturen:

Hvorfor er Fibonacci-tallene interessante Vi skal altså programmere sekvensen gitt ved F n = F n 1 + F n 2 og F 1 = 1 Fibonacci.java class Fibonacci { static int fib(int n) { if (n == 1) return 1; else return fib(n-1) + fib(n-2); public static void main(string[] arg) { int antall = Integer.parseInt(arg[0]); for (int i = 1; i <= antall; i++) System.out.println("Fib(" + i + ") = " + fib(i));

Hva gikk galt? Dette gikk ikke bra: $ java Fibonacci 10 Fib(1) = 1 Exception in thread "main" java.lang.stackoverflowerror at Fibonacci.fib(Fibonacci.java:4) at Fibonacci.fib(Fibonacci.java:4) at Fibonacci.fib(Fibonacci.java:4) at Fibonacci.fib(Fibonacci.java:4) at Fibonacci.fib(Fibonacci.java:4) at Fibonacci.fib(Fibonacci.java:4) at Fibonacci.fib(Fibonacci.java:4). Problemet oppstår i kallet fib(2) som så kaller på 1 fib(1) (går OK) 2 fib(0) som kaller på fib(-1) som...

Hva må vil alltid passe på? Huskeregler for rekursiv programmering Når vi programmerer rekursivt, må vi alltid huske på Det rekursive kallet må være et kall på et enklere problem. Vi må sørge for at det trivielle problemet håndteres skikkelig.

Hvordan bør det da programmeres? En riktig versjon av koden: Fibonacci2.java class Fibonacci2 { static int fib(int n) { if (n <= 2) return 1; else return fib(n-1) + fib(n-2); public static void main(string[] arg) { int antall = Integer.parseInt(arg[0]); for (int i = 1; i <= antall; i++) System.out.println("Fib(" + i + ") = " + fib(i));

Hvordan flyttes springeren i sjakk? En komplett springertur Et vanlig hobbyproblem i sjakk er: Flytt springeren slik at den er innom alle rutene på et sjakkbrett. Dette kan vi løse ved å prøve alle muligheter.

Hvordan flyttes springeren i sjakk? class KnightsTour { static int[][] brett; static int bredde, bredde2; static void flytt(int trekk, int x, int y) { if (x < 0 x >= bredde) return; if (y < 0 y >= bredde) return; if (brett[x][y] > 0) return; brett[x][y] = trekk; if (trekk == bredde2) { tegnbrett(); System.exit(1); flytt(trekk+1, x+2, y+1); flytt(trekk+1, x+2, y-1); flytt(trekk+1, x+1, y+2); flytt(trekk+1, x+1, y-2); flytt(trekk+1, x-1, y+2); flytt(trekk+1, x-1, y-2); flytt(trekk+1, x-2, y-1); flytt(trekk+1, x-2, y-1); brett[x][y] = 0; static void tegnbrett() { for (int iy = bredde-1; iy >= 0; iy--) { for (int ix = 0; ix < bredde; ix++) { System.out.printf("%3d",brett[ix][iy]); System.out.println(); public static void main(string[] arg) { bredde = Integer.parseInt(arg[0]); bredde2 = bredde * bredde; brett = new int[bredde][bredde]; flytt(1, 0, 0); System.out.println("Ingen løsninger!");

Hvordan flyttes springeren i sjakk? Da kan vi finne løsningene: $ javac KnightsTour.java $ java KnightsTour 1 1 $ java KnightsTour 2 Ingen løsninger! $ java KnightsTour 3 Ingen løsninger! $ java KnightsTour 4 Ingen løsninger! $ java KnightsTour 5 25 14 9 18 5 8 19 6 23 10 13 24 15 4 17 20 7 2 11 22 1 12 21 16 3 $ java KnightsTour 6 14 27 22 31 16 29 21 32 15 28 23 4 26 13 24 5 30 17 33 20 11 8 3 6 12 25 2 35 18 9 1 34 19 10 7 36 $ java KnightsTour 7 39 24 43 28 41 8 19 44 27 40 25 20 5 10 23 38 29 42 9 18 7 30 45 26 21 6 11 4 37 22 35 32 3 14 17 46 31 2 15 48 33 12 1 36 47 34 13 16 49

Hvordan flytte ringene på en enkel måte Hanois tårn Den oppdiktete bakgrunnen for spillet fra 1883 er: I et tempel i Hanoi står tre staker, og på den venstre ligger 60 ringer av ulik størrelse, sortert med den minste øverste. Oppgaven er å flytte ringene til den høyre staken, men Ringene må flyttes én og én. En ring må aldri legges oppå en mindre ring. Den midtre stolpen kan benyttes underveis.

Hanois tårn Hanois tårn med 1 ring

Hanois tårn Hanois tårn med 2 ringer

Hanois tårn Hanois tårn med 3 ringer

Slik løser vi problemet Programmere Hanois tårn Vi kaller de tre stolpene A, B og C. Vi skal flytte alle ringene fra A til C. For å kunne flytte den største ringen, må vi først flytte alle de andre ringene til hjelpestolpen B. Så kan vi flytte den største ringen fra A til C. Etterpå må vi flytte alle ringene fra hjelpestolpen B til C (oppå den største ringen). Og da er jobben gjort.

Slik løser vi problemet Hanoi.java class Hanoi { static void flytt(int n, char fra, char via, char til) { if (n == 1) { System.out.println("Flytt " + fra + " til " + til); else { flytt(n-1, fra, til, via); flytt(1, fra, via, til); flytt(n-1, via, fra, til); public static void main(string[] arg) { int antall = Integer.parseInt(arg[0]); flytt(antall, A, B, C );

Slik løser vi problemet $ java Hanoi 1 Flytt A til C $ java Hanoi 2 Flytt A til B Flytt A til C Flytt B til C $ java Hanoi 3 Flytt A til C Flytt A til B Flytt C til B Flytt A til C Flytt B til A Flytt B til C Flytt A til C $ java Hanoi 4 Flytt A til B Flytt A til C Flytt B til C Flytt A til B Flytt C til A Flytt C til B Flytt A til B Flytt A til C Flytt B til C Flytt B til A Flytt C til A Flytt B til C Flytt A til B Flytt A til C Flytt B til C

Hvor lang tid vil det ta? Hvor mange trekk trenger man? Leketøysvarianten har 8 ringer. Man må da foreta 2 8 1 = 255 flyttinger. Den originale «legenden» sier at det er 60 ringer. Da trengs 2 60 1 10 18 flyttinger. Hvis vi antar at munkene kan flytte én ring hvert sekund, vil det ta omtrent 36 534 658 086 år før verden går under.

Kort repetisjon av lister Enveis lister Navn: start Type: Node Navn: neste Type: Node Navn: data Navn: neste Type: Node Navn: data Navn: neste null Type: Node Navn: data Type: T class Node Type: T class Node Type: T class Node??? class T class T class T

Hvordan kan vi enklest snu en slik liste? Oppgave: Skriv en metode reverse som snur listen til Navn: start Type: Node Navn: neste null Type: Node Navn: data Navn: neste Type: Node Navn: data Navn: neste Type: Node Navn: data Type: T class Node Type: T class Node Type: T class Node??? class T class T class T

Metoden reverse Lenkeliste.java class Lenkeliste<T> implements Liste<T> { class Node { Node neste = null; T data; Node(T x) { data = x; void reverse(node pre) { if (neste == null) start = this; else neste.reverse(this); neste = pre; private Node start = null; public void reverse() { if (start!= null) start.reverse(null);

Metoden reverse Navn: start Type: Node reverse Navn: neste Type: Node Navn: pre reverse Navn: neste Type: Node Navn: pre reverse Navn: neste null Type: Node Navn: pre Type: Node if (neste==null) start = this; else neste.reverse(this); neste = pre; Type: Node if (neste==null) start = this; else neste.reverse(this); neste = pre; Type: Node if (neste==null) start = this; else neste.reverse(this); neste = pre; Navn: data Navn: data Navn: data class Node Type: T class Node Type: T class Node Type: T??? class T class T class T

Hva er viktig å vite om rekursjon? Oppsummering Sitat fra læreboken The key to the successfull design of a recursive method is not to think about it. Men husk allikevel alltid på at den rekursive metoden må kalle på en enklere versjon av problemet vi må håndtere det trivielle problemet.