Récursivité - Département d`informatique et de recherche
Transcription
Récursivité - Département d`informatique et de recherche
IFT1025 Récursivité c 2008 Marc Feeley Copyright c 2008 Marc Feeley Recursivite page 1 Définition c 2008 Marc Feeley Recursivite page 2 Définition tirée d’un dictionnaire humoristique... RÉCURSIVITÉ : Si vous ne comprennez pas, allez voir “récursivité” Définition plus sérieuse c 2008 Marc Feeley Recursivite page 3 • Lorsqu’un système contient une autoréférence (ou une copie de lui-même) on dit que ce système est récursif • En informatique, la récursivité est un des concepts de programmation les plus importants • Permet de résoudre des problèmes complexes en les décomposant en problèmes plus petits • Vous connaissez déjà des systèmes récursifs... • Voyons quelques exemples tirés de la nature... Domaine minéral c 2008 Marc Feeley Recursivite page 4 Une montagne (générée par ordinateur) Domaine animal c 2008 Marc Feeley Recursivite page 5 Un coquillage de nautilus Domaine végétal (1) c 2008 Marc Feeley Recursivite page 6 Une vraie fougère et une générée par ordinateur Domaine végétal (2) c 2008 Marc Feeley Recursivite page 7 Du romanesco (hybride broccoli/choux-fleur) Très récursif! Domaine végétal (3) c 2008 Marc Feeley Recursivite page 8 Un arbre réel et un arbre généalogique des ascendants Effet droste (1) c 2008 Marc Feeley Recursivite page 9 Un parfait et un imparfait Effet droste (2) c 2008 Marc Feeley Recursivite page 10 Escalier c 2008 Marc Feeley Recursivite page 11 • (vision itérative) Un escalier de hauteur h c’est : une séquence de h marches • (vision récursive) Un escalier de hauteur h c’est : une marche suivie d’un escalier de hauteur h − 1 Monter un escalier en Java c 2008 Marc Feeley Recursivite page 12 • Version itérative : static void monter_escalier( int h ) { for (int i = 1; i <= h; i++) monter_marche(); } • Version récursive : static void monter_escalier( int h ) { if (h == 1) monter_marche(); else { monter_marche(); monter_escalier( h-1 ); } } Récursivité en action c 2008 Marc Feeley Recursivite page 13 • Que fait l’appel monter escalier( 3 ) ? monter_escalier( 3 ) = monter_marche(); monter_escalier( 2 ); = monter_marche(); monter_marche(); monter_escalier( 1 ); = monter_marche(); monter_marche(); monter_marche(); • Même effet que la version itérative, c’est-à-dire 3 appels à monter marche() Jeu "devinez le nombre de 1 à 100" c 2008 Marc Feeley Recursivite page 14 • Le jeu : • La personne #1 choisit secrètement un nombre X de 1 à 100 • La personne #2 propose à la personne #1 un nombre P de 1 à 100, qui lui répond • “c’est exact!” si X = P • “plus bas” si X < P • “plus haut” si X > P • La personne #2 doit répéter jusqu’à ce que le nombre soit deviné Recherche dichotomique c 2008 Marc Feeley Recursivite page 15 • La stratégie la plus efficace est d’utiliser une recherche dichotomique • La personne #1 choisit secrètement le nombre 37 • #2 propose 50... #1 répond “plus bas” • #2 propose 25... #1 répond “plus haut” • #2 propose 37... #1 répond “c’est exact!” • Il faut au maximum 7 tentatives Recherche dichotomique récursive en Java c 2008 Marc Feeley Recursivite page 16 • rechercher( min, max ); fait la recherche en supposant que min ≤ X ≤ max static final int EXACT = 0; static final int PLUS_BAS = -1; static final int PLUS_HAUT = 1; static int lire_reponse() { ... } static void rechercher( int min, int max ) { if (min == max) System.out.println( "c’est " + min ); else { int n = (min + max) / 2; System.out.println( "est-ce que c’est " + n ); switch (lire_reponse()) { case PLUS_BAS : rechercher( min, n-1 ); break; case PLUS_HAUT: rechercher( n+1, max ); break; } } } Recherche dichotomique lorsque X = 37 c 2008 Marc Feeley Recursivite page 17 • Le jeu débute par l’appel rechercher( 1, 100 ); rechercher( 1, 100 ); = System.out.println( "est-ce que c’est 50" ); switch (lire_reponse()) { ... } = System.out.println( "est-ce que c’est 50" ); rechercher( 1, 49 ); = System.out.println( "est-ce que c’est 50" ); System.out.println( "est-ce que c’est 25" ); switch (lire_reponse()) { ... } = System.out.println( "est-ce que c’est 50" ); System.out.println( "est-ce que c’est 25" ); rechercher( 26, 49 ); = System.out.println( "est-ce que System.out.println( "est-ce que System.out.println( "est-ce que switch (lire_reponse()) { ... } c’est 50" ); c’est 25" ); c’est 37" ); /* fini */ La recette de récursivité c 2008 Marc Feeley Recursivite page 18 • S’assurer que le problème peut se décomposer en un ou plusieurs sous-problèmes de même nature • Identifier le cas de base qui est le plus petit problème qui ne se décompose pas en sous-problèmes • résoudre(P ) = • si P est un cas de base, le résoudre directement • sinon • décomposer P en sous-problèmes P1 , P2 ,... • résoudre récursivement P1 , P2 ,... • combiner les résultats pour obtenir la solution pour P Courbe fractale de Koch c 2008 Marc Feeley Recursivite page 19 • Courbe qui a une similarité propre : Niveaux de courbes c 2008 Marc Feeley Recursivite page 20 niveau 0 niveau 1 niveau 2 niveau 3 niveau 4 niveau 5 Algorithme c 2008 Marc Feeley Recursivite page 21 • Pour tracer une courbe de Koch de A à B : • niveau = 0, tracer une ligne de A à B : A B 0 1 • niveau = N , décomposer en 4 segments comme ci-dessous et tracer une courbe de Koch de niveau N − 1 à la place de chaque segment 1/3 1/3 A 0 60 1/3 1/3 o 1/3 2/3 B 1 Classe utilitaire c 2008 Marc Feeley Recursivite page 22 • Classe pos représentant des coordonnées 2D : class pos { public double x, y; public pos( double xx, double yy ) { x = xx; y = yy; } public pos add( pos p ) { return new pos( x+p.x, y+p.y ); } public static pos rot( double dist, double angle ) { double a = 3.1415926 * angle / 180; return new pos( dist * Math.cos(a), dist * Math.sin(a) ); } } B dist angle A Classe koch c 2008 Marc Feeley Recursivite page 23 static void koch( int niv, pos p0, double dist, double angle ) { pos p4 = p0.add( pos.rot( dist, angle ) ); if (niv == 0) System.out.println( "("+p0.x+","+p0.y+")-("+p4.x+","+p4.y+")" ); else { pos p1 = p0.add( pos.rot( dist/3, angle ) ); pos p2 = p1.add( pos.rot( dist/3, angle+60 ) ); pos p3 = p0.add( pos.rot( 2*dist/3, angle ) ); koch( koch( koch( koch( niv-1, niv-1, niv-1, niv-1, p0, p1, p2, p3, dist/3, dist/3, dist/3, dist/3, angle ); angle+60 ); angle-60 ); angle ); } } static void tracer() { koch( 5, new pos( 0, 0 ), 1, 0 ); } Koch en Scheme c 2008 Marc Feeley Recursivite page 24 (define (koch niv p0 dist angle) (let ((p4 (add p0 (rot dist angle)))) (if (= niv 0) (line p0 p4) (let* ((p1 (p2 (p3 (koch ((koch ((koch ((koch (ESSAYER (add p0 (rot (add p1 (rot (add p2 (rot niv 1) p0 (/ niv 1) p1 (/ niv 1) p2 (/ niv 1) p3 (/ (/ dist (/ dist (/ dist dist 3) dist 3) dist 3) dist 3) 3) angle))) 3) (+ angle 60)))) 3) (- angle 60))))) angle) (+ angle 60)) (- angle 60)) angle))))) Tours de Hanoï c 2008 Marc Feeley Recursivite page 25 • Le jeux est composé de 3 poteaux (A, B, C) et de N disques troués de différentes tailles • Au départ, les N disques sont en ordre de grandeur sur le poteau A • Le but est de déplacer les N disques au poteau C, en déplaçant seulement un disque à la fois, et en ne mettant jamais un disque sur un disque plus petit • État de départ avec 4 disques: 1 2 3 4 A B C Tours de Hanoï (suite) c 2008 Marc Feeley Recursivite page 26 • Comment résoudre ce problème? • Il existe un algorithme récursif très simple • Pour déplacer une pile de N disques de X à Y il faut • déplacer une pile de N − 1 disques de X à Z • déplacer le disque restant de X à Y • déplacer une pile de N − 1 disques de X à Y Tours de Hanoï (suite) c 2008 Marc Feeley Recursivite page 27 static void hanoi( int N, if (N > 0) { hanoi( N-1, X, Z, Y System.out.println( hanoi( N-1, Z, Y, X } } char X, char Y, char Z ) { ); "deplacer de " + X + " a " + Y ); ); static void go() { hanoi( 4, ’A’, ’C’, ’B’ ); } Execution c 2008 Marc Feeley Recursivite page 28 % javac hanoi.java % java hanoi deplacer de A a B deplacer de A a C deplacer de B a C deplacer de A a B deplacer de C a A deplacer de C a B deplacer de A a B deplacer de A a C deplacer de B a C deplacer de B a A deplacer de C a A deplacer de B a C deplacer de A a B deplacer de A a C deplacer de B a C