Rekursjon som programmeringsteknikk

Like dokumenter
Kapittel 12: Rekursjon

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

Kapittel 12: Rekursjon

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

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

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

UNIVERSITETET I OSLO

Rekursiv programmering

Kap.8 Sortering og søking sist oppdatert 16.03

EKSAMEN med løsningsforslag

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; }

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

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

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

UNIVERSITETET I OSLO

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

UNIVERSITETET I OSLO

OPPGAVE 1 OBLIGATORISKE OPPGAVER (OBLIG 1) (1) Uten å selv implementere og kjøre koden under, hva skriver koden ut til konsollen?

INF1000 (Uke 15) Eksamen V 04

INF1000 (Uke 15) Eksamen V 04

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

INF1010 notat: Binærsøking og quicksort

programeksempel Et større En større problemstilling Plan for forelesingen Problemstillingen (en tekstfil) inneholdt ordet "TGA"

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

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

EKSAMEN 6108/6108N PROGRAMMERING I JAVA Alt trykt og skriftlig materiale.

En algoritme for permutasjonsgenerering

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

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

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

INF1010 Sortering. Marit Nybakken 1. mars 2004

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

Gjennomgang prøveeksamen oppgave 1, 2, 4, 5, 7

TOD063 Datastrukturer og algoritmer

UNIVERSITETET I OSLO

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

Algoritmer og datastrukturer Eksamen

Dagens forelesning. Java 13. Rollefordeling (variant 1) Rollefordeling (variant 2) Design av større programmer : fordeling av roller.

Fra Kap.10 Binære søketre (BS-tre) Sist oppdatert Definere en abstrakt datastruktur binært søketre. Vise hvordan binær søketre kan brukes

Forelesning inf Java 4

INF Uke 10. Ukesoppgaver oktober 2012

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

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

Uke 8 Eksamenseksempler + Ilan Villanger om studiestrategier. 11. okt Siri Moe Jensen Inst. for informatikk, UiO

UNIVERSITETET I OSLO

Rekursiv programmering

Forelesning inf Java 5

Forelesning inf Java 5

Algoritmer og datastrukturer Kapittel 1 - Delkapittel 1.8

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

EKSAMEN. Dato: 9. mai 2016 Eksamenstid: 09:00 13:00

Introduksjon til objektorientert programmering

UNIVERSITETET I OSLO

Oppgave 1. Sekvenser (20%)

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

Backtracking som løsningsmetode

INF1000 Metoder. Marit Nybakken 16. februar 2004

Eksamen i emnet INF100 Grunnkurs i programmering (Programmering I) Løsningsforslag

UNIVERSITETET I OSLO

EKSAMENSFORSIDE Skriftlig eksamen med tilsyn

LITT OM OPPLEGGET. INF1000 EKSTRATILBUD Stoff fra uke September 2012 Siri Moe Jensen EKSEMPLER

Gjennomgang av eksamen H99

EKSAMEN. Algoritmer og datastrukturer

PG4200 Algoritmer og datastrukturer Forelesning 3 Rekursjon Estimering

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

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

MAT1030 Diskret Matematikk

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

UNIVERSITETET I OSLO

Repetisjon: Statiske språk uten rekursive metoder (C1 og C2) Dagens tema Kjøresystemer (Ghezzi&Jazayeri 2.6, 2.7)

Lenkelister. Lister og køer. Kopi av utvalgte sider fra forelesningen.

Dagens tema Kjøresystemer (Ghezzi&Jazayeri 2.6, 2.7)

LO118D Forelesning 2 (DM)

Kapittel 9: Sortering og søking Kort versjon

OPPGAVE 5b og 8b Java Kode

Algoritmer og datastrukturer Kapittel 9 - Delkapittel 9.1

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

Algoritmer og datastrukturer Kapittel 2 - Delkapittel 2.1

Kap 9 Tre Sist oppdatert 15.03

Feilmeldinger, brukerinput og kontrollflyt

MAT1030 Plenumsregning 1

Løse reelle problemer

Algoritmer og datastrukturer Kapittel 3 - Delkapittel 3.1

Algoritmer og datastrukturer Løsningsforslag

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

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

UNIVERSITETET I OSLO

EKSAMEN. Emne: Algoritmer og datastrukturer

Løse reelle problemer

Hva er en algoritme? INF HØSTEN 2006 INF1020. Kursansvarlige Ragnar Normann E-post: Dagens tema

Transkript:

Rekursjon Kap.7 Sist oppdatert 15.02.10 Rekursjon som programmeringsteknikk 10-1

Rekursiv tenkning Rekursjon er en programmeringsteknikk der en metode kan kalle seg selv for å løse problemet. En rekursiv definisjon er en definisjon som bruker ord eller begreper som er definert i selve definisjonen. I noen situasjoner kan en rekursiv definisjon være en passende måte å uttrykke et begrep på. 10-2

Rekursive definisjoner Gitt følgende liste av tall: 24, 88, 40, 37 En slik liste kan defineres rekursivt.: En LISTE er et: tall eller et: tall komma LISTE Dvs., en LISTE kan være et tall, eller et tall etterfulgt av et komma etterfulgt av en LISTE. Begrepet LISTE blir brukt til å definere seg selv. 10-3

FIGURE 7.1 Gjennomgå den rekursive definisjonen av en liste. 10-4

Uendelig rekursjon Alle rekursive definisjoner må ha en ikkerekursiv del. Hvis de ikke har, så er det ingen måte å terminere den rekursive stien på. En definisjon uten en ikke-rekursiv del forårsaker en uendelig rekursjon. Dette problemet ligner på en uendelig løkke- - -- med definisjonen selv som forårsaker den uendelig løkkegjennomgang. Den ikke-rekursive delen er ofte kalt basistilfellet. 10-5

Rekursive definisjoner Matematiske formler er ofte uttrykt rekursivt. N!, for et positivt heltall N, er definert å være produktet av alle helltall mellom 1 og N inkludert. Definisjonen av fakultet kan uttrykkes rekursivt.: 1! = 1 N! = N * (N-1)! Et tall vi tar fakultet av er definert ved ledd av et annet tall vi tar fakultet av og dette gjentas inntil basistilfellet er 1! 10-6

Rekursiv programmering En metode i Java kan kalle seg selv. Hvis den er satt opp på denne måten kalles den en rekursiv metode. Koden til en rekursiv metode må struktureres for å håndtere både basistilfelle(r) og det rekursive kallet. Hvert rekursive kall settes opp med nye parametre og nye lokale variable. Når metoden fullføres vil kontrollen returnere til den metoden som kalte den (en annen forekomst av seg selv). Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-7

Generelt for rekursive metodekall F(*) Gjøre litt Kall Gjøre resten F(*) Gjøre litt Kall Gjøre resten F(*) Gjøre litt Kall Gjøre resten F(*) Gjøre litt møte utgang Gjøre resten Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-8

Realisering vha systemstabel Ved hvert rekursivt kall stables det på en ramme som utgjør plass til: - parametre, eventuell returverdi, og returadresse. Etter n kall vil vi ha n slike rammer på systemstabelen. Ved hver retur fra en rekursiv metode stables det av en slik ramme. Gitt at metoden har en returverdi. Når rekursjonen er ferdig, vil svaret ligge på systemstabelen. Vi behøver ikke vite hvordan en slik ramme ser ut for å kunne programmere rekursivt. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-9

Rekursiv programmering Vi betrakter problemet med å beregne summen av alle tall mellom 1 og N inkludert. Hvis N er 5 vil summen være 1 + 2 + 3 + 4 + 5 Problemet kan uttrykkes rekursivt ved: Summen av 1 til N er N pluss summen av 1 til N-1 Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-10

FIGURE 7.2 Summen av tallene 1 til N, definert rekursivt. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-11

Rekursiv programmering public int sum(int n){//summere //de n første positive heltall int result; if (n == 1) result = 1; else result = n + sum(n-1); return result; }//metode Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-12

FIGURE 7.3 Rekursive kall til metoden sum. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-13

Krav til rekursive løsninger: Delproblemet er mindre enn hele problemet. Delproblemet kan enten løses direkte (basistilfelle) eller rekursivt ved rekursive kall. Løsningen av delproblemet kan kombineres med løsninger av andre delproblemer for å oppnå løsningen til hele problemet. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-14

Rekursjon som velegnet problemløsningsteknikk Når problemet naturlig kan deles i mindre enklere deloppgaver som ligner på hverandre og videre at vi får enklere og mer elegant kode. Pga alle metodekall og bruk av stabel vil det alltid eksistere en ikke-rekursiv løsning som er mer effektiv. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-15

Rekursjon vs. Iterasjon Rekursjon: - Bruk av kontrollstruktur: (if, if else, ) - Gjentatt metodekall Iterasjon: - Bruk av løkkestruktur(for, while, ) Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-16

Labyrint(eks. på fornuftig bruk av rekursjon) La oss bruke rekursjon for å finne en sti gjennom en labyrint. Det fins en sti gjennom labyrinten fra lokasjon x hvis det fins en sti fra en av nabolokasjonene til x. Vi merker hver lokasjon vi besøker som besøkt og forsøker å finne en sti fra en av de ubesøkte naboene. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-17

Labyrint Rekursjon vil bli brukt til å holde rede på stien gjennom labyrinten. Realiseringen bakom rekursjon er en run-time -stabel. Basis-tilfellene er: En blokkert lokasjon, eller at mål nås. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-18

Listing 7.1 class Labyrintspill{//Oppretter en nylabyrint, skriver ut opprinnelige form, prøver å løse og skriver ut den endelige formen. public static void main (String[] args){ Labyrint labyrint = new Labyrint(); System.out.println(labyrint); if (labyrint.gjennomgå(0, 0)) System.out.println ("Labyrinten ble gjennomgaatt!"); else System.out.println ("Det var ingen mulig sti."); System.out.println (labyrint); } }//metode Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-19

Listing 7.2 Representerer en labyrint av tegn. Målet er å gå fra øvre venstre hjørne til nedre høyre hjørne ved å følge en sti av 1'enere class Labyrint{ private final int FORSØKT = 3; private final int STI = 7; private int[][] gridd = { {1,1,1,0,1,1,0,0,0,1,1,1,1}, {1,0,1,1,1,0,1,1,1,1,0,0,1}, {0,0,0,0,1,0,1,0,1,0,1,0,0}, {1,1,1,0,1,1,1,0,1,0,1,1,1}, {1,0,1,0,0,0,0,1,1,1,0,0,1}, {1,0,1,1,1,1,1,1,0,1,1,1,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,1,1,1,1,1,1,1,1,1,1,1}}; Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-20

Listing 7.2 (forts.) /*************************************** Forsøk på rekursiv gjennomgang av labyrinten. Setter inn et spesielt tegn ('3') for å indikere at lokasjon er blitt forsøkt og et annet spesielt tegn '7' for at lokasjonen eventuelt er en del av løsningen. ************************************** Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-21

public boolean gjennomgå(int rekke, int kolonne) { boolean ferdig = false; if (gyldig (rekke, kolonne)) { gridd[rekke][kolonne] = FORSØKT;//cellen er forsøkt if (rekke == gridd.length-1 && kolonne == gridd[0].length-1) ferdig = true; // spillet er løst else{ ferdig = gjennomgå(rekke+1,kolonne);// ned if (!ferdig) ferdig = gjennomgå(rekke,kolonne+1);// høyre if (!ferdig) ferdig = gjennomgå(rekke-1,kolonne);// opp if (!ferdig) ferdig = gjennomgå(rekke, kolonne-1);//venstre } if (ferdig) //denne lokasjonene er en del av den endelige stien gridd[rekke][kolonne] = STI; } return ferdig;}//metode Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-22

//Avgjør om en spesifisert lokasjon er gyldig. private boolean gyldig(int rekke,int kolonne){ boolean resultat = false; /*sjekker om cellen er innenfor gridd */ if(rekke >= 0 && rekke < gridd.length && kolonne >= 0 && kolonne < gridd[rekke].length) /* sjekker om cellen ikke er blokkert og ikke forsøkt tidligere */ if (gridd[rekke][kolonne] == 1) resultat = true; return resultat; }//metode Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-23

// Returnerer labyrinten som en streng. public String tostring (){ String resultat = "\n"; for (int rekke = 0; rekke < gridd.length; rekke++){ for (int kolonne = 0; kolonne < gridd[rekke].length; kolonne++) resultat += gridd[rekke][kolonne] + ""; resultat += "\n"; } return resultat; } }//class Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-24

1110110001111 1011101111001 0000101010100 1110111010111 1010000111001 1011111101111 1000000000000 1111111111111 Kjøring Labyrinten ble gjennomgaatt! 7770110001111 3077707771001 0000707070300 7770777070333 7070000773003 7077777703333 7000000000000 7777777777777 Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-25

Tårnene i Hanoi (Eks på fornuftig bruk av rekursjon) Tre pinner og et gitt antall ringer. Ringene har ulike størrelser og er initielt plassert på en pinne med den største ringen på bunnen og mindre ringer plassert oppå etter avtagende størrelse med den minste på toppen. Målet er å flytte alle ringene fra en pinne til en annen etter følgende regler: Kun en ring kan flyttes om gangen. En ring kan ikke plasseres over en mindre. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-26

FIGURE 7.6 Tårnene i Hanoi Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-27

FIGURE 7.7 Løsning med tre ringer. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-28

Tårnene i Hanoi (NB! Rekursiv tenkning) For å flytte en stabel av n ringer fra den originale startpinnen til målpinnen: Flytt de n-1 øverste ringene fra den opprinnelige pinnen til den ekstra pinnen (mellom) Flytt den største ringen fra den opprinnelige pinnen til målpinnen. Flytt de n-1 ringene fra den ekstra pinnen til målpinnen. Baistilfellet er når stabelen inneholder kun en ring. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-29

Tårnene i Hanoi Antall flyttinger øker eksponensielt når antall ringer øker. Enkel rekursiv løsning. En iterativ løsning er mye mer kompleks. (Dere finner kanskje en på nettet) Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-30

Listing 7.3, 7.4 // Tårn i Hanoi class SpillTårnIHanoi{ public static void main (String[] args){ TårnIHanoi tårn = new TårnIHanoi (4); tårn.spill(); }//main }//class Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-31

// Tårn i Hanoi class TårnIHanoi{ private int antallringer; //Setter opp spillet med spesifisert antall ringer. public TårnIHanoi (int startringer) antallringer = startringer; }//metode //Utfører det første kallet til flyttringer. Flytter ringene fra tårn 1 til tårn 3 ved å bruke tårn 2. public void spill(){ flyttringer (antallringer, 1, 3, 2); }//metode Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-32

//Flytter det spesifiserte antallet ringer fra et tårn til et annet ved å flytte n-1 ringer, deretter flytte en ring og til slutt flytte den de n-1 ringene. private void flyttringer (int antringer, int start, int slutt, int temp){ if (antringer == 1)// Basistilfellet flyttenring (start, slutt); else{//rolleskifte fra, til, mellom, flyttringer (antringer-1, start, temp,slutt); flyttenring (start, slutt); flyttringer (antringer-1, temp, slutt,start); } }//metode Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-33

/*Skriver ut mellomresultatene ved flytting. private void flyttenring(int start, int slutt){ System.out.println ("Flytt en ring fra " + start + til + slutt); }//metode Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-34

Kjøring med 4 ringer, ant flyttinger:2 4 1= 15 flytt en ring fra 1 til 2 flytt en ring fra 1 til 3 flytt en ring fra 2 til 3 flytt en ring fra 1 til 2 flytt en ring fra 3 til 1 flytt en ring fra 3 til 2 flytt en ring fra 1 til 2 flytt en ring fra 1 til 3 flytt en ring fra 2 til 3 flytt en ring fra 2 til 1 flytt en ring fra 3 til 1 flytt en ring fra 2 til 3 flytt en ring fra 1 til 2 flytt en ring fra 1 til 3 flytt en ring fra 2 til 3 Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-35

Analyse av rekursive algoritmer. Når vi analyserer en løkke, bestemmer vi orden av løkkekroppen og multipliserer med antall ganger løkken utføres. Rekursiv analyse foregår tilsvarende. Vi avgjør orden av metodekroppen og multipliserer den med orden av rekursjonen (antall ganger den rekursive definisjonen/kall er brukt). Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-36

Analyse av sum (summere de n første pos. heltall). public int sum (int n){ int result; if (n == 1) result = 1; else result = n + sum(n-1); return result; }//metode Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-37

Analyse av sum Den relevante operasjonen i metoden sum er å legge sammen to verdier, O(1). n antall ganger rekursive kall. Rekursjonen er O(n). Det betyr at hele algoritmen er O(n). Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-38

Analyse av Tårnene i Hanoi I Tårnene i Hanoi er størrelsen på problemet antall ringer. Operasjonen som er interessant er flytting av en ring. La a n være antall flyttinger når antallet ringer er n. Med (n-1) ringer vil vi ha a n-1 flyttinger og a n = 2 a n-1 +1. Se tidligere lysbilde. Har vi kun en ring klarer vi oss med en flytting, slik at a 1 = 1. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-39

Analyse av Tårnene i Hanoi Unntatt for basistilfellet vil hvert rekursivt kall resultere i to rekursive kall (2 a n-1 ). a n = 2 a n-1 +1. Med n ringer får vi: a n = 2 n - 1. Med 64 ringer får vi (2 64-1) flyttinger For å løse et problem med n ringer gjør vi altså 2 n -1 flyttinger. Derfor er algoritmen O(2 n ), altså eksponensiell kompleksitet. Copyright 2005 Pearson Addison-Wesley. All rights reserved. 10-40