310 likes | 497 Views
Recursieve Datastructuren. Inductie !! Om recursie te begrijpen moeten we eerste recursie begrijpen. Het beschrijven van een begrip in termen van zichzelf Klassiek voorbeeld: Recursieve methode faculteit int faculteit( int n ) { if ( n == 1 ) { return 1; } else {
E N D
Recursieve Datastructuren • Inductie !! • Om recursie te begrijpen moeten we eerste recursie begrijpen. • Het beschrijven van een begrip in termen van zichzelf • Klassiek voorbeeld: • Recursieve methode faculteit int faculteit( int n ) { if ( n == 1 ) { return 1; } else { return n * faculteit( n-1 ); } } Base Case
Recursieve Datastructuren • Recursie als problem solver • Torens van Hanoi • Kennis van het probleem • Mooie code. • public void move( int n, Toren a, Toren b, Toren c ) { • if ( n > 0 ) { // there is some to move • move ( n - 1, a, c, b ); // move all but one to c • b.add( a.remove() ); // move last tot b • move ( n - 1, c, b, a ); // move all from c to b • } // else done • } A C B
Recursieve Datastructuren • Torens van Hanoi: • aantal benodigde stappen H voor N stenen geeft rij • H0 = 0, H1 = 1, H2 = 3, H3 = 7 (0,1,3,7….) • Recurente betrekking • H0 = 0 • Hn = 2 * Hn-1 + 1 voor n > 0 • Zie ook faculteit: (zie ook code) • f0 = 1 • fn = n * fac( n-1 ) • Of Fibonacci (oefening)
Recursieve Datastructuren • Fibonacci • Het ‘konijnenrijtje’ gaf de oplossing voor een probleempje dat Fibonacci in 1202 formuleerde: • Een boer koopt op de markt in Pisa twee jonge konijnen: een mannetje en een vrouwtje. De eerste maand brengt dit stel nog geen kleintjes voort, maar na de tweede maand worden de eerste twee konijnen geboren: een mannetje en een vrouwtje. Gedurende de daaropvolgende maanden brengt dit eerste stel konijnen steeds twee konijnen van verschillend geslacht ter wereld. Maar ook de nakomelingen van dit stel gaan, nadat ze een maand oud zijn, zich voortplanten en brengen elke maand een stel konijnen ter wereld.Het Fibonaccirijtje geeft aan hoeveel konijnenparen de boer in de opeenvolgende maanden heeft, als er vanuit wordt gegaan dat geen enkel stel doodgaat
Recursieve Datastructuren • Fractals (Mandelbrot) • Berekendn door recursie • bv Koch’s sneeuwvlok: • // deel van de vlok • public void drawLine( Graphics g, int x0, int y0, int x1, int y1, int level) { • //System.out.println("Draw ("+ ++count +") at depth "+level); • g.drawLine( x0,y0, x1,y1 ); • if ( level > 0 ) { • int xa = x0 + (x1-x0)/3; • int ya = y0 + (y1-y0)/3; • int xb = x1 - (x1-x0)/3; • int yb = y1 - (y1-y0)/3; • int xc = x0 + (x1-x0)/2 - (y1 - y0)/3; • int yc = y0 + (y1-y0)/2 + (x1 - x0)/3; • drawLine(g, x0,y0, xa,ya, level-1); • drawLine(g, xa,ya, xc,yc, level-1 ); • drawLine(g, xc,yc, xb,yb, level-1 ); • drawLine(g, xb,yb, x1,y1, level-1 ); • } • } Koch’s sneeuwvlok “Mandelbrot”
Recursieve Datastructuren • Recursieve Objecten • Aanroep zelfde methode, ander object van zelfde type • Gebruikt bij lijsten, bomen en grafen. • Recursieve lijst (met Sentinel) RecList RecList RecList Sentinel public int size() { int size = 0; if (! isSentinel() ) { size = 1 + next.size(); } return size; } “E” “B” “G”
Recursieve Datastructuren RecList RecList RecList RecList • Recursieve lijst: add(“F”) • Plaats object in sentinel, nieuwe sentinal “F” “E” “B” “G” RecList RecList RecList RecList RecList “E” “B” “G” “F”
Recursieve Datastructuren RecList RecList RecList RecList • Recursieve lijst: addAfter(“B”, “F”) • Plaats object in sentinel, nieuwe sentinal “E” “B” “F” “G” RecList RecList RecList RecList RecList “E” “B” “G” “F”
Recursieve Datastructuren RecList RecList RecList RecList • Recursieve lijst: remove(“B”) • Verwijder volgende RecList ipv huidige “E” “B” “G” RecList RecList RecList RecList “E” “B” “G”
Recursieve Datastructuren public int size() { int size = 0; if ( ! isSentinel() ) { size = 1 + left.size() + right.size(); } return size; } public V get( K aKey) { V found = null; if ( ! isSentinel() ) { int compare = key.compareTo( aKey ); if ( compare == 0 ) { found = value; } else if ( compare > 0 ) { left.get( aKey ); } else { right.get( aKey ); } } return found; } • Recursieve Boom (TreeMap) • Gesorteerd met (Comparabel)key en value • Zoeksnelheid : 2log n ipv n/2 “G” “D” “S” “A” “K” “U”
Recursieve Datastructuren • Recursieve Boom (TreeMap) • Key moet Comparable (methode compareTo) zijn, • kun je afdwingen met Generics ! public class TreeMap<K extends Comparable<K>, V> {…} • TreeMap<String, Iets> tree • put(“E”, iets); • put(“Z”, ietsAnders); tree “G” left right “D” “S” “A” “K” “U” “E” “Z”
Recursieve Datastructuren • Recursieve Boom (TreeMap) • remove(“S”) -> opzoeken -> gat opvullen met left.largest -> largest removen tree tree “G” “G” left right left right “D” “S” “D” “L” “A” “E” “K” “U” “A” “E” “K” “U” right.smallest() “L” left.largest() Wordt sentinel
Recursieve Datastructuren • Recursieve Boom als lijst • Inorder: ((A)D(E))G((K(L))S(U)) • Preorder: G(D(A)(E))(S(K(L))(U)) • Postorder: ((A)(E)D)(((L)K)(U)S)G tree “G” left right “D” “S” “A” “E” “K” “U” “L”
Recursieve Datastructuren • Recursieve Boom groeit scheef ! Sneller zoeken bij balans ofwel minder hoogte Balanseren na put en remove ! • Weight Balanced (duur) Swimlane RD.1: WBSTree • Implementeren • Testen • Meten tov java.util.TreeMap • AVL (todo?) • RedBlack (todo?) tree “G” left right “D” “S” “A” “E” “K” “U” “L”
Recursieve Datastructuren Torens van Hanoi in H stappen • Verplaats een voor een de stenen van pilaar 1 naar pilaar 3m, eventueel via pilaar 2. Er mag telkens maar èèn steen tegelijk verplaatst worden en nooit een grotere op een kleinere steen. • Hoeveel stappen heb je nodig: mbv recurrente betrekking: H0 = 0 Hn = 2*Hn-1+1 voor n > 0 Vermoeden: Hn = 2n -1: bewijs mbv volledige inductie public void move( int n, T a, T b, T c ) { if ( n > 0 ) { // there is some to move move ( n - 1, a, c, b ); // all but one to c b.add( a.remove() ); // move last tot b move ( n - 1, c, b, a ); // all from c to b } // else done }
Recursieve Datastructuren • Torens van Hanoi in H stappen • Recurrente betrekking: H0 = 0 Hn = 2*Hn-1+1 voor n ≥ 0 • Vermoeden: Hn = 2n -1: bewijs mbv volledige inductie • Voor n = 0 geldt: H0 = 0 en 20 - 1 = 1 – 1 = 0 • Stel: Hn = 2n – 1 voor k ≥ 0 => Hn+1 = 2*Hn+1 = 2*(2n–1)+1 = 2n+1–2+1 = 2n+1-1 • Bewijs: Hn = 2n-1 voor elke n ≥ 0
Recursieve Datastructuren Wiskundig Intermezzo Rijen, Reeksen Rekenkundige rij: is van de vorm: a0 = a an = an-1 + v voor n > 0 Voorbeeld: a0 = 2, v = 3 an = an-1 + 3 voor n > 0 Dit is de rij 2, 5, 8, 11, 14, 17, … met expliciete definitie: an = 2 + n*3 voor n = 0, 1, 2, … Merk op: bij een rekenkundige rij is het verschil tussen twee opeenvolgende getallen constant
Recursieve Datastructuren Wiskundig Intermezzo Rijen, Reeksen Rekenkundige reeks: is de som van de termen van een rekenkundige rij: 1 + 2 + 3 + 4 + 5 + 6 + 7 + ….. + 100 = ? 2 + 5 + 8 + 11 + 14 + 17 + ….. + 302 = ? Oplossing van Gauss: 1 + 2 + 3 + 4 + … + 100 100 + 99 + 98 + 97 + … + 1 + 101 + 101 + 101 + 101 + … + 101 100 = 1+ 2+ 3+ … + 100 = 100 * 101/2 = 5050 i= 1 n Algemeen: (a+iv) = a+(a+v)+(a+2v)+…+(a+nv) = ½ (2a+nv)(n+1) i=0 ∑ ∑
Recursieve Datastructuren Wiskundig Intermezzo Rijen, Reeksen Meetkundige rij is in de vorm: a0 = a an = r* an-1 voor n > 0 (r heet ‘reden’) Voorbeeld: a0 = 2 an = 3*an-1 voor n > 0 (reden = 3) Dit is de rij: 2, 6, 18, 54, 162 …. met expliciete definitie: an = 2*3n voor n = 0,1,2 …. Bij een meetkundige rij is het quotiënt van de twee opeenvolgende getallen constant !
Recursieve Datastructuren Wiskundig Intermezzo Rijen, Reeksen Meetkundige reeks is de som van de termen van een meetkundige rij Sn = a+ar+ar2+ar3+...+ +...+arn Er geldt Sn = a+ar+ar2+ar3+...arn r*Sn = ar+ar2+ar3+...arn+arn+1 - Sn –r*Sn= a - arn+1 ofwel: (1-r)*Sn = a*(1 - rn+1) Dus als r ≠ 1 => Sn = a*(1 - rn+1) / (1- r) n a*ri = a*(1-rn+1) / (1 – r) i=0 ∑
Recursieve Datastructuren Grafen het probleem van Köngsberg Leonard Euler gebruikte een graaf (1736).
Recursieve Datastructuren Grafen Graaf: Knopen(vertices) verbonden met buurknopen door zijden(edges) Toepassing: • Routeplanners • Computer netwerken • Informatiesystemen • Proplem solving (doolhof, project planning, pathfinding…. • etc Verbindingsmatrix (r->c)
Recursieve Datastructuren Grafen, varianten • Enkelvoudige graaf • Meervoudige graaf • (E/M) Gerichte graaf • (E/M, G) Gewogen graaf EIN MAS AMS RTM
Recursieve Datastructuren Grafen, doorzoeken • Depth first • Voor elke buur bezoek buur bezoek diens buren • Breath first • Elke buur in queue • Voor elke buur in queue bezoek buur diens buren in queue
Recursieve Datastructuren Grafen, Depth first Start bij knoop 1 bezoek ( knoop ) { doe iets markeer knoop als bezocht // cycle detection (sync) voor elke buurknoop { als buurknoop niet bezocht bezoek (buurknoop ) } } }
Recursieve Datastructuren Grafen, Breath first Start bij knoop 1 maak wachtrij plaats startknoop in wachtrij zolang knopen in wachtrij { haal knoop uit wachtrij doe iets met knoop voor elke buurknoop { als buurknoop niet bezocht plaats buurknoop in wachtrij markeer buurknoop als geplaatst } } }
Recursieve Datastructuren Virtuele Grafen, Kannengiet probleem Definieer toestand (2 kannen) bv (8,5) Vanuit ene toestand (0,0) naar andere (8,0) Elke toestand is een knoop Buurknopen conform spelregels Let op cycles Vind ik het kortste pad ?? Demo …..
Recursieve Datastructuren publicclass Situation { privateint largeVolume; privateint smallVolume; public Situation( int aLargeVolume, int aSmallVolume ) { largeVolume = aLargeVolume; smallVolume = aSmallVolume; } publicint getLargeVolume() { return largeVolume; } publicint getSmallVolume() { return smallVolume; } publicboolean equals( Object other ) { assert other instanceof Situation: “Must be Situation"; Situation situation = (Situation)other; return largeVolume == situation.largeVolume && smallVolume == situation.smallVolume; } public String toString() { return "("+largeVolume+","+smallVolume+")"; } } Virtuele Grafen, Kannengiet probleem Definieer toestand (2 kannen) bv (8,5) Vanuit ene toestand (0,0) naar andere (8,0)
Recursieve Datastructuren public boolean solve() { List<Situation> visited = new ArrayList<Situation>(); Situation start = new Situation( 0, 0 ); return solve( start, visited ); } public boolean solve( Situation situation, List<Situation> visited ) { boolean finished = isFinished( situation ); visited.add( situation ); // mark visited if ( finished ) { System.out.println("Finished : "+ situation); } else { List<Situation> neighbours = getPosibilities( situation ); for ( Situation neighbour: neighbours ) { if ( ! visited.contains( neighbour ) ) { finished = solve( neighbour, visited ); if ( finished ){ break; } } } } if ( finished ) { System.out.println( "->"+situation ); // shortest path? } return finished; } Virtuele Grafen, Kannengiet probleem Probeer alle toestanden Depth first
Recursieve Datastructuren public List<Situation> getPosibilities( Situation from ) { int largeVolume = from.getLargeVolume(); int smallVolume = from.getSmallVolume(); List<Situation> situations = new ArrayList<Situation>(); // make large empty situations.add( new Situation( 0, smallVolume ) ); // make small empty situations.add( new Situation( largeVolume, 0 ) ); // make large full situations.add( new Situation( LARGE, smallVolume ) ); // make small full situations.add( new Situation( largeVolume, SMALL ) ); // pour large to small if ( largeVolume < SMALL-smallVolume ) { situations.add( new Situation( 0, smallVolume+largeVolume ) ); } else { situations.add( new Situation( largeVolume-(SMALL-smallVolume), SMALL ) ); } // pour small to large if ( smallVolume < LARGE-largeVolume ) { situations.add( new Situation( largeVolume+smallVolume, 0 ) ); } else { situations.add( new Situation( LARGE, smallVolume-(LARGE-largeVolume) ) ); } return situations; } Virtuele Grafen, Kannengiet probleem Achterhaal de buren !
Recursieve Datastructuren Grafen en problem solving, Oefening: maak gewogen, gerichte graaf (deadline 22 dec) te gebruiken in Swimlane RDS.2 Puzzeldoolhof Deadline 12 januari