Vous êtes sur la page 1sur 8

Université Paris Diderot JAVA

MASS L2 Année 2007-2008

TD n◦7 - Correction
Récursivité

Exercice 1 Tableaux bidimensionnels


Écrire une méthode static int minMax(int[][] t) renvoyant le plus petit maximum de
chaque ligne de t.
Correction : Il est pratique de commencer par écrire une fonction auxiliaire permettant de calculer le
maximum d’une ligne.

static int maxLigne(int[] t)


{
int r=t[0];
for (int i=1; i<t.length; i++)
if (r < t[i])
r=t[i];
return r;
}

static int minMax(int[][] t)


{
int r=maxLigne(t[0]);
for (int i=1; i<t.length; i++)
{
int a=maxLigne(t[i]);
if (r > a)
r=a;
}
return r;
}

On peut aussi tout écrire dans une seule méthode, mais celà va être moins lisible :

static int minMax(int[][] t)


{
int r=t[0][0];
for (int j=1; j<t[0].length; j++)
if (r < t[0][j])
r=t[0][j];

//r contient le maximum de la première ligne

for (int i=1; i<t.length; i++)


{
int maxi=t[i][0];
for (int j=1; i<t.length; i++)
{
if (maxi < t[i][j])
maxi = t[i][j];
}

1
if (r > maxi)
r=maxi;
}
return r;
}

Dans les exercices sur la récursivité, l’usage de boucles for est interdit !

Exercice 2 Récursivité
1. Écrire une méthode récursive static int fact(int n) permettant de calculer la facto-
rielle de n.
Correction :
Attention : outre l’appel récursif, toutes les méthodes récursives doivent conteinir un critère d’arrêt.
S’il n’y a pas de critère d’arrêt ou s’il n’est pas bon, on va avoir une récursion à l’infini, qui va
provoquer une erreur à l’exécution. C’est par exemple le cas pour le code suivant :
static void stupide()
{
stupide();
}
où stupide() fait des appels en cascade d’elle-même sans jamais s’arrêter.
static int fact(int n)
{
if (n==0) return 1; //critère d’arr^
et
return n*fact(n-1); //appel récursif

}


2. Écrire une méthode récursive static binome(int n, int p) permettant de calculer un


coefficient binomial.
Correction :
static int binome(int n, int p)
{
if (n<0 || p<0 || p>n) return 0;
if (p==0 || p==n) return 1;
return binome(n-1, p-1)+binome(n-1, p);
}


3. En remarquant que xp = (x(p/2) )2 si p est pair, et xp = x(x(p/2) )2 si p est impair, écrivez


une méthode static exp(double x, int n) calculant xn
Correction :
On appelle cet algorithme exponentiation rapide.

2
static double exp(double x, int n)
{
if (n==0) return 1;
if (n%2==0)
{
double a=exp(x, n/2);
return a*a;
}
else
{
double a=exp(x, n-1/2);
return a*a*x;
}
}
Ainsi, pour calculer 237 , on aura des appels à exp(2, 37), exp(2, 18), exp(2, 9), exp(2, 4),
exp(2, 2), exp(2, 1), exp(2, 0).
En revanche si on utilisait une exponentiation naı̈ve :
static double expNaive(double x, int n)
{
if (n==0) return 1;
return x*exp(x, n-1);
}
le même calcul nécessiterait des appels à exp(2, 37),exp(2, 36),exp(2, 35), . . ., exp(2, 0), ce
qui est beaucoup plus couteux.
Dans le second cas, le calcul de xn a une complexité linéaire O(n), alors que dans le premier cas,
on peut montrer qu’elle est logarithmique (O(log(n))).


Exercice 3 Récursivité et tableaux


1. Écrire une méthode récursive static int sum(int n, int[] t) calculant la somme des
n premiers éléments de t.
Correction : Pour faire la somme des n premiers éléments, on prend la somme des n − 1 premiers,
et on lui ajoute le nème (c’est-à-dire t[n-1]).
static int sum(int n, int[] t)
{
if (n==0) return 0;
return t[n-1]+sum(n-1, t);
}

2. En utilisant une méthode récursive auxiliaire, écrire une méthode static affiche(int[] t)
permettant d’afficher le tableau t.
Correction :
Commençons par écrire une méthode permettant d’afficher les n premiers éléments d’un tableau.
Pour afficher les n premiers éléments, on affiche les n − 1 premiers, puis on affiche le nème .
static void afficheN(int n, int[] t)
{
if (n==0) return;

3
afficheN(n-1, t);
System.out.println(t[n-1]);
}

il ne reste plus alors qu’à afficher les t.length premiers éléments de t pour l’afficher entièrement.
static void affiche(int[] t)
{
afficheN(t.length, t);
}

3. Modifier la méthode précédente pour que le tableau soit affiché dans l’ordre inverse.
Correction :
Il suffit, dans afficheN d’afficher l’élément courant avant d’afficher ce qui précede :
static void afficheN(int n, int[] t)
{
if (n==0) return;
System.out.println(t[n-1]);
afficheN(n-1, t);
}

Exercice 4 On parle de récursivité croisée lorsque deux fonctions s’appellent l’une l’autre
récursivement.
Les fonctions suivantes sont censées donner la parité d’un nombre entier : cela sera-t-il le
cas pour toutes les valeurs entières positives ?
import fr.jussieu.script.Deug;

class PairImpair{

static boolean pair (int n){


if (n==0)
return true;
else
return impair(n-1);
}
static boolean impair (int n){
if (n==1)
return true;
else
return pair(n-1);
}

public static void main (String[] args) {


int p = Deug.readInt();
Deug.println("pair? "+ pair(p) + " impair? " + impair(p));
}
}

4
Correction : Regardons ce qui se passe lors d’un appel à pair(3). En suivant l’exécution du code pas
à pas, on va avoir les appels suivants :
pair(3)
impair(2)
pair(1)
impair(0)
pair(-1)
impair(-2)
...
La condition d’arrêt n’est donc pas bonne. Un autre élément montrant que ce code ne peut pas
marcher est qu’aucune des deux méthodes ne peut jamais renvoyer false.
On pourrait les modifier de la manière suivante pour qu’elles fonctionnent :

import fr.jussieu.script.Deug;

class PairImpair{

static boolean pair (int n){


if (n==0)
return true;
else
return impair(n-1);
}
static boolean impair (int n){
if (n==0)
return false;
else
return pair(n-1);
}

public static void main (String[] args) {


int p = Deug.readInt();
Deug.println("pair? "+ pair(p) + " impair? " + impair(p));
}
}

Exercice 5 Tours de Hanoı̈

On dispose de n plateaux de taille différentes, et de 3 tiges, numérotées de 0 à 2.


Initialement, tous les plateaux sont situés sur la tige i. Le but est de les transférer sur la
tige j, en respectant les règles suivantes :
– On ne peux déplacer qu’un plateau à la fois
– Les plateaux doivent toujours rangés par taille décroissante sur une tige.
1. Résolvez le problème à la main si n = 2, i = 0 et j = 2.
Correction :

5
– On transfère le petit plateau de 0 à 1.
– On transfère le grand plateau de 0 à 2.
– On transfère le petit plateau de 1 à 2.
Si vous n’êtes pas convaincus, faites un dessin . . .


2. Résolvez le problème à la main si n = 3, i = 0 et j = 2.


Correction :
– On transfère le petit plateau de 0 à 2.
– On transfère le plateau moyen de 0 à 1.
– On transfère le petit plateau de 2 à 1.
(ce faisant, on a déplacé 2 plateaux de 0 vers 1).
– On tranfère le grand plateau de 0 vers 2.
– On transfère le petit plateau de 1 à 0.
– On transfère le plateau moyen de 1 à 2.
– On transfère le petit plateau de 0 à 2.
(ce faisant, on a déplacé 2 plateaux de 1 vers 2).


3. Supposez qu’un de vos amis sache résoudre le problème pour un certain n, et n’importe
quels i et j. On vous demande de résoudre le problème pour n + 1. Vous avez le droit
d’utiliser l’aide de votre ami. Comment vous y prenez-vous ?
Correction : On demande à l’ami de déplacer n plateaux de i à l’emplacement qui n’est ni i ni j.
On déplace ensuite le dernier plateau (le plus gros) de i à j. On remet à contribution l’ami pour
déplacer les n plateaux vers j.


4. Écrire un algorithme récursif void hanoi(int n, int i, int j) affichant la suite des
instructions à effectuer pour résoudre le problème.
Par exemple hanoi(2, 0, 2) devra renvoyer
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2

Correction :
Nous allons écrire une fonction auxiliaire pour trouver le numéro de l’emplacement qui n’est ni i
ni j :
static int autre(int i, int j)
{
if (i==0)
{
if (j==1)
return 2;
else
return 1;
}
else
if (i==1)
{
if (j==0)

6
return 2;
else
return 0;
}
else
{
if (j==0)
return 1;
else
return 0;
}
}
On déduit l’algorithme de la question ci-dessus, sans oublier la condition d’arrêt.
static void hanoi(int n, int i, int j)
{
if (n==1)
{
System.out.println(¨Déplacer un plateau de ¨+i+¨ à ¨+j);
return;
}
int a=autre(i, j);
hanoi(n-1, i, a);
System.out.println(¨Déplacer un plateau de ¨+i+¨ à ¨+j);
hanoi(n-1, a, j);
}
À titre d’exemple, voici la liste des instructions pour déplacer 6 plateaux de 0 à 2 :
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2
Déplacer un plateau de 0 à 1
Déplacer un plateau de 2 à 0
Déplacer un plateau de 2 à 1
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2
Déplacer un plateau de 1 à 0
Déplacer un plateau de 2 à 0
Déplacer un plateau de 1 à 2
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2
Déplacer un plateau de 0 à 1
Déplacer un plateau de 2 à 0
Déplacer un plateau de 2 à 1
Déplacer un plateau de 0 à 1
Déplacer un plateau de 2 à 0
Déplacer un plateau de 1 à 2
Déplacer un plateau de 1 à 0
Déplacer un plateau de 2 à 0
Déplacer un plateau de 2 à 1
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2

7
Déplacer un plateau de 0 à 1
Déplacer un plateau de 2 à 0
Déplacer un plateau de 2 à 1
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2
Déplacer un plateau de 1 à 0
Déplacer un plateau de 2 à 0
Déplacer un plateau de 1 à 2
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2
Déplacer un plateau de 1 à 0
Déplacer un plateau de 2 à 0
Déplacer un plateau de 2 à 1
Déplacer un plateau de 0 à 1
Déplacer un plateau de 2 à 0
Déplacer un plateau de 1 à 2
Déplacer un plateau de 1 à 0
Déplacer un plateau de 2 à 0
Déplacer un plateau de 1 à 2
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2
Déplacer un plateau de 0 à 1
Déplacer un plateau de 2 à 0
Déplacer un plateau de 2 à 1
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2
Déplacer un plateau de 1 à 0
Déplacer un plateau de 2 à 0
Déplacer un plateau de 1 à 2
Déplacer un plateau de 0 à 1
Déplacer un plateau de 0 à 2
Déplacer un plateau de 1 à 2
Je déconseille d’essayer ça chez vous. . .


Vous aimerez peut-être aussi