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