Récursivité Définition récursive dun problème. Critère darrêt et convergence. Performance des...

Post on 04-Apr-2015

104 views 1 download

Transcript of Récursivité Définition récursive dun problème. Critère darrêt et convergence. Performance des...

Récursivité

Définition récursive d’un problème. Critère d’arrêt et convergence. Performance des algorithmes récursifs. Résolution d’un problème à l’aide de la récursivité.

2

Récursivité

Bourgeois gentilhomme (Acte II Scène IV) de Molière

Le héros, Monsieur Jourdain, veut connaître toutes les manières « galantes »d'écrire un billet.

De la phrase Belle Marquise, vos beaux yeux, me font mourir d'amour,il pourrait tirer

Vos beaux yeux, belle Marquise, d'amour me font mourir, puisVos beaux yeux, me font mourir, belle Marquise, d'amour, puisVos beaux yeux, me font mourir d'amour, belle Marquise etc.

Comment Monsieur Jourdain devrait-il procéder pour engendrer toutes cespermutations?

Le mieux pour lui pour être sûr d'y arriver est d'utiliser un procédé récursif.

On construit toutes les permutations de la phrasevos beaux yeux -- me font mourir -- d'amour; puis, dans ces permutations,on insère en première, deuxième, troisième et quatrième positionle morceau de phrase belle Marquise.

3

Récursivité : générateur de courbes fractales

générateur forme initiale arbre fractale

4

Récursivité

Une fonction ou une procédure récursive s’appelle elle-même.

Exemple I : Calcul de n!

#include <iostream.h>#include <cassert>

int Factorielle(int n)// Calcule la factorielle de n.//// Paramètre d'entrée :// n : un entier positif ou nul.//// Valeur de renvoi.// la valeur de n!{

assert(n >= 0);if (n == 0 || n == 1) return 1;return n * Factorielle(n - 1);

}

5

Récursivité

void main(){

int n;cout << "Entrez un nombre entier positif ou nul : ";cin >> n;cout << "La factorielle de " << n << " est : " << Factorielle(n) << endl;

}

Exemple II : Calcul du nième nombre de Fibonacci (Fn).

Fn =1 si n = 1 ou 2,

Fn-1 + Fn-2 si n > 2.

6

Récursivité

#include <iostream.h>#include <cassert>int Fibonacci(int n)// Calcule le n ième nombre de Fibonacci.//// Paramètre d'entrée :// n : un entier positif.// Valeur de renvoi.// la valeur du n ième nombre de Fibonacci.{

assert(n > 0);if (n == 1 || n == 2) return 1;return Fibonacci(n - 1) + Fibonacci(n - 2);

}void main(){

int n;cout << "Entrez un nombre entier positif : ";cin >> n;cout << "Le " << n << " ieme nombre de Fibonacci est : "

<< Fibonacci(n) << endl;}

7

Efficacité

Dans ces exemples, les fonctions récursives ne sont pas efficaces.

int Fibonacci(int n){

assert(n > 0);int F1 = 1;int F2 = 1;int resultat;

if (n == 1 || n == 2) return 1;for (int i = 3; i <= n; i++){

resultat = F1 + F2;F1 = F2;F2 = resultat;

}return resultat;

}

Évite de recalculerplusieurs fois

le même nombre.

Les appels récursifssont coûteux.

n = 50

Je n’ai pas réussi àobtenir une réponseavec l’approche récursive.

n = 47 Mauvais résultat

8

Efficacité

Fibonacci(5)

Fibonacci(4) Fibonacci(3)

Fibonacci(3) Fibonacci(2)

Fibonacci(2) Fibonacci(1)

Fibonacci(2) Fibonacci(1)

Beaucoup de redondance.

9

Coûteux en espace mémoire

Les fonctions récursives exigent aussi beaucoup d’espaces mémoires.

int Essai(int n)// Calcule la sommation suivante : 1 + 2 + ... + n.//// Paramètre d'entrée :// n : un entier positif.//// Valeur de renvoi.// la valeur de la sommation.{

assert(n > 0);int i;

if (n == 1) return 1;i = n + Essai(n - 1);return i;

}

10

Coûteux en espace mémoire

Essai(4)

n i

4 ?

3 ?Essai(3)

2 ?Essai(2)

1 ?Essai(1)

pile

Appels successifs Retours d’appels

Essai(4) 4 ?

3 ?Essai(3)

2 3Essai(2)

pile

Essai(4) 4 ?

3 6Essai(3)

Essai(4) 4 10

11

Usage d’une pile

#include <iostream.h>

void Lecture(){

char ch;

cin >> ch;if (ch != '#'){

Lecture();cout << ch;

}}

void main(){

Lecture();cout << endl;

}

abc#

cba

Affichage d’une chaîne inversée.

12

Stratégie pour résoudre un problème

La récursivité peut être utile pour résoudre un problème pouvant êtredécomposé en sous-problèmes de même type mais de plus petite taille.

3 étapes :

Décomposez le problème original en sous-problèmes ouenvisagez différentes façons pour simplifier les entrées.

Combinaison des solutions des sous-problèmes pour obtenirla solution du problème original.

Identification d’un cas trivial et de sa solution(sans appel récursif).

13

Exemple : la tour de Hanoï

Énoncé :

n disques de diamètres différents sont posés les uns sur les autres, par ordrede taille décroissante, sur un socle A,

il s’agit de les transférer sur le socle B en utilisant le socle C.

Déplacements autorisés : prendre un disque au sommet d’une des piles,le poser sur un disque plus grand ou

sur un socle vide.

État initialA B C

14

Exemple : la tour de Hanoï

Stratégie :

Transférer n – 1 disques de A à C en utilisant B comme socleintermédiaire.

Déplacer le disque qui reste en A sur B.

Transférer les n – 1 disques de C en B en utilisant A commesocle intermédiaire.

Cas trivial : si n est égale à 1 alors déplacer le disque de A dans B.

Cas général :

On dit que le jeu des Tours de Hanoï a pour origine unrituel des prêtres de Brahman pour prédire la fin du monde.Les prêtres de Brahman utilisaient n = 64 disques.

15

Exemple : la tour de Hanoï

#include <iostream.h>

void Hanoi(int n, char A, char B, char C){

if (n == 1) cout << "Deplacer le disque " << A<< " dans " << B << ".\n";

else{

Hanoi(n - 1, A, C, B);cout << "Deplacer un disque " << A

<< " dans " << B << ".\n";Hanoi(n - 1, C, B, A);

}}void main(){

Hanoi(5, 'A', 'B', 'C');cout << endl;

}

16

Algorithme d’Euclide : PGCD de 2 entiers

PGCD(m, n) =

PGCD(n, m) si n > m

m si n ≤ m, n = 0

PGCD(n, m % n) si n ≤ m, n > 0

#include <iostream.h>#include <cassert>int PGCD( int m, int n){

assert(m != 0 || n != 0);if(n != 0) return PGCD(n, m % n);return m;

}void main(){

int m, n;cin >> m >> n;cout << PGCD(m, n);cout << endl;

}

17

Comment déterminer si une chaîne est un palindrome ?

Une chaîne égale à elle-même en inversant tous ses caractères. Ex. : rotor

#include <iostream.h>#include <string.h>bool est_palindrome(char * s){

int i = strlen(s);if(i <= 1) return true;if(s[0] != s[i-1]) return false;char * raccourci = new char[i-1];strncpy(raccourci, s+1, i-2);raccourci[i-2] = '\0';return est_palindrome(raccourci);

}void main(){

char * chaine = "rotor";cout << est_palindrome(chaine) << endl;

}

18

Comment déterminer si une chaîne est un palindrome ?

Approche plus élégante.

#include <iostream.h>#include <string.h>bool souschaine_est_palindrome(char * s, int debut, int fin){

if (debut >= fin) return true;if(s[debut] == s[fin])

return souschaine_est_palindrome(s, debut+1, fin-1);else return false;

}bool est_palindrome(char * s){

return souschaine_est_palindrome(s, 0, strlen(s) - 1);}void main(){

char * chaine = "rotor";cout << est_palindrome(chaine) << endl;

}