Td corrigé La récursivité pdf

La récursivité

2) Définition : En pratique ... d'utiliser les rangs de ces arguments (le premier paramètre, .... Écrire une fonction récursive chiffre( n, k) qui permet de retourner.




part of the document



cursive :


Ces conseils sont illustrés par l'exemple suivant :

Écrire une fonction récursive permettant de calculer la somme
des chiffres d'un entier n positif (exemple : n = 528, la somme
des chiffres de n est 15).



1. Observer le problème afin de :

a) décrire la condition d'arrêt : quand peut-on
trouver "facilement" la solution ?
(une solution triviale) :

Si on a le choix entre n = 528 et n = 8, il est
certain qu'on choisit n = 8. La somme des chiffres
de 8 est 8.


Conclusion : Si n a un seul chiffre, on arrête. La
somme des chiffres est n lui-même.

if ( n < 10 ) return n;


b) de réduire le problème à un problème d'ordre
inférieur pour que la condition d'arrêt soit
atteinte un moment donné :

somChif(528) 8 + somChif(52)
8 + ( 2 + somChif(5) )
8 + 2 + 5

D'un problème de 3 chiffres, on réduit d'abord à un
problème de deux chiffres : somChif(52). Celui-ci
est réduit à celui d'un seul chiffre : somChif(5).
On rencontre la condition d'arrêt.


else
return n % 10 + somChif ( n / 10 ) ;

2. Écriture de la fonction :


int somChif ( int n )
{
if ( n < 10 ) /* condition d'arrêt */
return n;
else
/* réduction du problème : */
return n % 10 + somChif ( n / 10 ) ;
}


Exercice :

Illustrer les conseils précédents pour écrire une fonction récursive
qui permet de calculer le produit de deux entiers positifs a et b.

Notes :

1. Si vous avez le choix entre : 12 x 456 et 12 x 0

lequel des deux calculs est le plus simple ?


2. 12 x 9 = 12 + 12 + 12 + ... + 12 ( 9 fois )
= 12 + (12 + 12 + ... + 12) ( 8 fois)

= 12 + 12 x 8

etc ...



4) Simulation :

Ne pas utiliser les "noms" des arguments. Il est préférable
d'utiliser les rangs de ces arguments (le premier paramètre,
le deuxième paramètre, etc ...)


Exemple 1 :

Soit la fonction récursive suivante :

int facto ( int n )
{
if ( n 1, exemple k = 3, on a :

chiffre (8724, 3)
chiffre ( 872, 2) (872 est 8724 / 10, 2 est 3-1)
chiffre ( 87, 1) (87 est 872 / 10, 1 est 2-1)


Solution :

int chiffre ( int n, int k )

{
if ( k == 1 ) /* le premier chiffre à partir de la droite */
return n % 10 ;
else
return chiffre ( n / 10, k - 1 ) ;
}



Exemple 3 : Tours de Hanoi.


Supposons qu'on dispose de 3 disques à la tour 1 et on aimerait
les déplacer à la deuxième tour en utilisant la tour 3 comme
intermédiaire.

Les règles du jeu sont les suivantes :

- les disques ont un diamètre différent
- on déplace un disque à la fois
- on n'a pas le droit de placer un disque de diamètre supérieur
sur un de diamètre inférieur.


état 0 :
| | |
--- | |
| | |
------- | |
| | |
----------- | |
| | |
---------------- ---------------- ----------------
Tour 1 Tour 2 Tour 3





état 1 : déplacer un disque de Tour 1 à Tour 2

| | |
| | |
| | |
------- | |
| | |
----------- --- |
| | |

---------------- ---------------- ----------------
Tour 1 Tour 2 Tour 3




état 2 : déplacer un disque de Tour 1 à Tour 3

| | |
| | |
| | |
| | |
| | |
----------- --- -------
| | |
---------------- ---------------- ----------------
Tour 1 Tour 2 Tour 3



état 3 : déplacer un disque de Tour 2 à Tour 3

| | |
| | |
| | |
| | ---
| | |
----------- | -------
| | |
---------------- ---------------- ----------------
Tour 1 Tour 2 Tour 3



état 4 : déplacer un disque de Tour 1 à Tour 2

| | |
| | |
| | |
| | ---
| | |
| ----------- -------
| | |
---------------- ---------------- ----------------
Tour 1 Tour 2 Tour 3



état 5 : déplacer un disque de Tour 3 à Tour 1

| | |
| | |
| | |
| | |
| | |
--- ----------- -------
| | |
---------------- ---------------- ----------------
Tour 1 Tour 2 Tour 3



état 6 : déplacer un disque de Tour 3 à Tour 2


| | |
| ------ |
| | |
--- ----------- |
| | |
---------------- ---------------- ----------------
Tour 1 Tour 2 Tour 3


état 7 : déplacer un disque de Tour 1 à Tour 2

| | |
| --- |
| | |
| ------ |
| | |
| ----------- |
| | |
---------------- ---------------- ----------------
Tour 1 Tour 2 Tour 3

Le processus sera plus compliqué et mêlant quand le nombre de
disques deviendra grand.

Solution :

#include

void deplacer (int n, int t1, int t2, int t3)
{
if ( n == 1 )
printf("De la tour %d à la tour %d\n", t1, t2) ;
else
{ deplacer (n-1, t1, t3, t2) ;
deplacer ( 1 , t1, t2, t3) ;
deplacer (n-1, t3, t2, t1) ;
}
}


void main()

{ int nbDisques ;

printf("Entrez le nombre de disques à déplacer ");
scanf ("%d", &nbDisques);

deplacer ( nbDisques, 1, 2, 3);

}



Note :

Une autre version possible de deplacer est :

void deplacer (int n, int t1, int t2, int t3)
{
if ( n > 0 )
{
deplacer (n-1, t1, t3, t2) ;
printf("De la tour %d à la tour %d\n", t1, t2) ;
deplacer (n-1, t3, t2, t1) ;
}
}


exécution :

Entrez le nombre de disques à déplacer 3

De la tour 1 à la tour 2
De la tour 1 à la tour 3
De la tour 2 à la tour 3
De la tour 1 à la tour 2
De la tour 3 à la tour 1
De la tour 3 à la tour 2
De la tour 1 à la tour 2

Exercice:


Simuler l'appel suivant :


deplacer (3, 1, 2, 3) ;


6) Tri rapide (Quick Sort) :


Supposons qu'on dispose du tableau t qui contient les 9
éléments suivants à trier :

t[0] t[1] t[2] t[3] t[4] t[5] t[6] t[7] t[8]
T%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%
Q% 43 Q% 75 Q% 23 Q% 46 Q% 55 Q% 12 Q% 64 Q% 77 Q% 33 Q%
Z%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%

L'idée de la méthode QuickSort est simple :

1) Pour la première fois, on tri le tableau au complet,
c'est-à-dire de l'indice 0 à l'indice (nbElement - 1)
(ici 8). Ceci correspond à l'appel suivant :

quickSort(t, 0, nbElement - 1) ;


2) On partitionne le tableau en deux côtés d'une valeur du pivot.
A gauche, on trouve des valeurs la valeur du pivot.

t[0] t[1] t[2] t[3] t[4] t[5] t[6] t[7] t[8]
T%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%P%P%P%P%P%W%
Q% 12 Q% 33 Q% 23 Q% 43 Q% 55 Q% 46 Q% 64 Q% 77 Q% 75 Q%
Z%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%P%P%P%P%P%]%
__________________ ^ _____________________________
valeurs 43
|
valeur du pivot
( 43 trouve sa bonne place
à l'indice du pivot 3 )

On verra plus loin la technique de la partition.

On réapplique de nouveau le QuickSort pour la partie gauche
(indices 0 à 2) et la partie droite (indices 4 à 8) du tableau.
Cette réapplication nous montre le concept de la récursivité.

Quelle est la condition d'arrêt ?

- on tri une partie du tableau quand elle contient au moins deux
valeurs à mettre en ordre. C'est-à-dire : l'indice gauche est
inférieur à l'indice droite. Sinon, la partie est triée.

Quelle est la réduction du problème à celui d'un ordre inférieur ?

- au lieu d'appliquer le QuickSort sur tout le tableau,
on l'applique sur deux sous-tableaux : celui à gauche
de l'indice du pivot et celui à droite de cet indice.
Chacun de ces deux sous-tableaux contient moins
d'éléments, ce qui fait accélérer le processus de tri
(i.e. de la répartition).


Exemple1 :

Cet exemple permet de voir la programmation de la méthode du tri
rapide. On utilise un petit tableau de 7 éléments dont la simulation
du tri sera présentée en classe :

int t[10] = { 20, 15, 80, 32, 10, 90, 46 } ;
int nbElem = 7 ;


Solution :


/* Fichier : Q_Sort1.A95 : Tri rapide avec Quick Sort

Matière principale : le tri rapide
*/

#include

void partitionner(int t[], int, int, int *) ; /* prototype */

/* données simple pour démontrer que le tri rapide fonctionne */
int t[10] = { 20, 15, 80, 32, 10, 90, 46 } ;
int nbElem = 7 ;

void afficher(int t[], int nbElem, char * quand)
{ int i ;

printf("\nContenu du tableau %s\n\n", quand);

for (i = 0 ; i < nbElem ; i++)
printf(" %3d", t[i]);
printf("\n\n");
}

void quickSort (int t[], int gauche, int droite)

{
int indPivot ;

if (gauche < droite)
{ partitionner (t, gauche, droite, &indPivot);
quickSort(t, gauche, indPivot - 1 );
quickSort(t, indPivot+1, droite);
}
}
void echanger(int * a, int * b) /* transmis par pointeur */
{

int tempo ;

tempo = *a , *a = *b, *b = tempo ; /* opérateur séquentiel "," */

}


void partitionner(int t[], int debut, int fin, int * indice)
{
int g = debut , d = fin ;
int valPivot = t[debut];

do
{ while (g