Djamal Rebaïne 1
Djamal Rebaïne 1
La récursivité
Une procédure est dite récursive si, et seulement si, elle fait appel à elle-même, soit directement soit indirectement
Djamal Rebaïne 2
Djamal Rebaïne 3
- (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
Un exemple
Version itérative :
static void monter_escalier( int h )
{
for (int i = 1; i <= h; i++)
monter_marche();
}
Version récursive :
void monter_escalier( int h )
{
if (h > 0)
monter_marche();
monter_escalier( h-1 );
}
Djamal Rebaïne 4
Djamal Rebaïne 5
Récursivité en action
• 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 3appels à monter marche()
Djamal Rebaïne6
Recette de récursivité
• S’assurer que le problème peut se décomposer en unou plusieurs sous-problèmes de même nature
• Identifier le cas de base qui est le plus petit problèmequi 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 obtenus pour P1, P2, …, pour obtenir la solution pour avoir la solution au problème de départ.
Djamal Rebaïne 7
Fonctionnement d’une fonctionrécursive
• Création d’une pile pour la sauvegarde entre autres des paramètres d’appels de la procédure et la l’adresse de retour.
Djamal Rebaïne 8
Calculer le factoriel de n, noté n!
• Le problème est: Calculer le factoriel d'un nombre entier donné en entrée.
• En entrée: Nous avons n nombre entiers qui sont plus grands ou égaux à 0.
• Sortie: Nous avons un nombre entier qui représente le factoriel de n.
Djamal Rebaïne 9
• Fonction principale• entier n nfact• lire n • si (n < 0) alors écrire “entrée négative: ” n• sinon• nfact factoriel(n)• écrire “la factorielle de ” n “est” nfact
• où factoriel satisfait le prototype
• entier factoriel(entier)
Djamal Rebaïne 10
Fonction factoriel
int factoriel(entier n) {
si (n < 1) retourner 1retourner n * factoriel(n-1)
}
Djamal Rebaïne 11
Comment le faire en assembleur?
On a besoin d’une pile!• En effet, à chaque appel récursif, la valeur du paramètre
n est sauvegardée dans la pile de travail. • Ce processus d’empilement est répété jusqu’à ce que le
paramètre actuel (de l’appel) n atteigne la valeur 0. Cela correspond à la fin de l’exécution de la fonction appelante.
• Ensuite, commence le dépilement, et l’exécution de la prochaine instruction de la fonction appelante est entamée. Ce processus de dépilement est répété jusqu’à ce qu’on atteigne la valeur de départ du paramètre n.
12Djamal Rebaine
Cela se traduit par le programme assembleur suivant
TITLE factoriel PILE segment stack dw 100 dup(?) Basdepile equ this wordPILE endsData segment N dw 4 fact dw ?Data endsCode segment assume CS:code, DS:Data, SS:Pile Debut: MOV AX,Data MOV DS,AX MOV AX,Pile MOV SS, AX ; initialise le segment de pile MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP mov BX,n; sauvegarde la valeur de n mov AX,BX Push AX call factoriel Fin: pop AX; le résultat calculé par la fonction factoriel est dans AX mov fact, AX mov AX,4c00h int 21h
Djamal Rebaïne 13
Factoriel proc near ; en utilisant la pile CMP AX,0 JA DEPILE MOV AX,1 JMP fin
DEPILE: ; dépiler jusqu’à ce n = 0 DEC AX PUSH AX ; factoriel(n-1) CALL FACTORIAL
RetourResultat: POP BX MUL BX fin: ret factoriel endp ; fin de la procédurecode ends end debut ; fin du programme code
Djamal Rebaïne 14Djamal Rebaïne 14
Calcul d’une somme par récursivité
Title sommerecursive; pour totaliser la somme de 1 jusqu’à n.PILE segment stack dw 100 dup(?) Basdepile equ this wordPILE endsData segment N dw 12 som dw ?Data endsCode segment assume CS:code, DS:Data, SS:Pile Debut: MOV AX,Data MOV DS,AX MOV AX,Pile MOV SS, AX ; initialise le segment de pile MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP
Djamal Rebaïne 15
mov CX,n; sauvegarde la valeur de n XOR AX,AX CALL sommerecursive Fin: pop AX; le résultat calculé par la fonction factoriel est dans
AX mov fact, AX mov AX,4c00h int 21h
Djamal Rebaïne 16
sommerecursive proc near ;
CMP CX,0
JNZ fin
mov cx, 0
Fin: push cx
dec cx
CALL sommerecursive; resultat est dans cx
pop ax
add ax,cx
fin: ret
factoriel endp ; fin de la procédure
code ends
end debut ; fin du programme code
Djamal Rebaïne 17
Inversion d’une chaine de caractères
• Donnée: S une chaine de caractères
• Question: Afficher S dans le sens inverse
Djamal Rebaïne 18
• Fonction principale
• ecrire “introdroduire la chaîne: ”
• inverser
Djamal Rebaïne 19
Fonction factoriel
Entête:entier factoriel(entier n)
Corps:lire car;
si car <> `.` inverser; afficher car;
Djamal Rebaïne 20
La fonction inverser fonctionne comme suit:
Tant que le caractère lu n’est pas le point,
continuer la lecture;
Arrivé au point, l’affichage commence.
Djamal Rebaïne 21
TITLE INVERSER-CHAINE
affiche macro chaine ; mov dx,offset chaine ; mov ah, 09h ; int 21hendm PILE segment stack dw 100 dup(?) Basdepile equ this wordPILE endsData segmentChaine db ‘introduire votre chaine’, 10,13, ‘$’Data endsCode segment assume CS:code, DS:Data, SS:PileDebut: MOV AX,Data MOV DS,AX MOV AX,Pile MOV SS, AX ; initialise le segment de pile MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP Affich chaine call inverser; APPEL DE LA FONCTION INVERSERFin: mov AX,4c00h int 21h
Djamal Rebaïne 22
inverser Proc near; les appels récursifs sont gérés exclusivement par la pile.
mov ah,1 ; lecture d’un caractère int 21hCMP AL,’.’ JNE dépiler; dépiler jusqu’à ce AL = ‘.’ CBW ; convertir le caractère en un mot
; ou alors faire mov AH,0 push AX
inverser
Depiler: POP AX mov AH,2 int 21 ret inverser; fin de la procédure
code ends; fin du programme principal end debut
inverser Proc near; dans cette version, les appels récursifs sont gérés ; exclusivement par la pile. Continuer: mov ah,1 ; lecture d’un caractère int 21h CMP AL,’.’ JNE dépiler ; dépiler jusqu’à ce AL = ‘.’ CBW ; convertir le caractère en un mot ; ou alors faire mov AH,0 push AX JMP continuer
Depiler: POP AX mov AH,2 int 21 JMP depilerret inverser; fin de la procédure
code ends; fin du programme principal end debut
Djamal Rebaïne 23
Djamal Rebaïne 24
• Rechercher l’élément C dans un tableau trié dans l’ordre croissant.
…………… …..
milieuL u
AC?
Djamal Rebaïne 25
• Int void recherche(C,L,u:entier; trouve:booleen) • { • si (u <= L) • { milieu = (u - L + 1) div 2;• si A[milieu] = C • return (milieu);• sinon si A[milieu] > C • recherche(C,L,milieu-1);• sinon recherche(C,milieu+1,u);• } • sinon return (-1);• }
Djamal Rebaïne 26
TITLE dichotomique
PILE segment stack dw 100 dup(?) Basdepile equ this wordPILE endsData segmenttableau db 1, 4, 8, 10, 18Donnee db 18Data endsCode segment assume CS:code, DS:Data, SS:PileDebut: MOV AX,Data MOV DS,AX MOV AX,Pile MOV SS, AX ; initialise le segment de pile MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP Lea SI, tableau; mov BX, SI Add BX, tableau[1] ; adresse du dernier élément du tableau push BX push SI call dichotoFin: mov AX,4c00h int 21h
Djamal Rebaïne 27
Dichoto proc near; pop SI pop BX CMP SI,BX JL fin ; continuer jusqu’à il n’y ait plus d’élément à rechercher
mov AX, BX ADD AX, SI Sub AX, 1 Mov DL,2 DIV DL CBW Mov CX,SI Mov SI, AX CMP [SI], donnee
jne appel mov AX,[SI] ret Appel: jg autreappel push BX push SI dichoto jmp finAutreappel: push SI push BX dichotoFin: ret code ends end debut
Djamal Rebaïne 28
Les nombres de Fibonacci
• Question: Écrire un programme qui calcule le nombre de Fibonacci défini comme suit:
1;0
1 n si ;
10
21
FF
FFF nnn
èmen
Djamal Rebaïne 29
TITLE fibonacciSPILE SEGMENT STACK DW 100 DUP(?)SPILE ENDSSDATA SEGMENT n dw 6SDATA ENDSSCODE SEGMENT ASSUME CS:SCODE,DS:SDATA DEBUT: mov ax,sdata mov ds,ax xor ax,ax xor bx,bx mov ax,n call fibo mov dl,al add dl,30h mov ah,2 int 21hsortie: MOV AX,4C00H INT 21H
Djamal Rebaïne 30
Fibo proc si1: cmp ax, 1 ; comparer ax avec 1 ja else ; si n<= 1, retourner 1 mov ax, 1 ; mettre 1 dans ax retelse: dec ax ; décrémenter ax de 1 c'est-à-dire égal à n-1 push ax ; mettre n-1 sur la pile call Fibo ; résultat dans ax pop bx ; rectifier la pile et bx = n-1 dec bx ; bx = n -2 push ax ; sauvegarder ax = Fibonacci(n-1) sur la pile mov ax,bx ; passe le n-1 à ax pour exécuter Fibonacci(n-2) call Fibo ; résultat dans ax = Fibonacci(n-2) pop bx ; bx = Fibonacci(n-1) add ax, bx ; ax = Fibonacci(n-2) + Fibonacci(n-1) retFibo endpSCODE ENDS END DEBUT
Djamal Rebaïne 31
Les tours de Hanoï
http://www.multimania.com/fmaire/jeux/hanoi/hanoi.html
http://members.aa.net/~wgf/Hanoi/Hanoi.html
Djamal Rebaïne 32
• Description du problème: Montrez comment déplacer n disques de tailles distinctes d'une tige A vers une tige B
• en utilisant comme tampon une tige C. Initialement seule la tige A contient les n disques ordonnés avec le plus petit sur le dessus. On ne doit déplacer qu'un seul disque à la fois. Il est interdit de placer un disque sur un autre plus petit.
• Entrée: Un entier n représentant le nombre de disques.
• Sortie: Une série d'instructions de la forme " déplacer i vers j" indiquant les déplacements nécessaires pour résoudre le problème.
Djamal Rebaïne 33
Djamal Rebaïne 34
• Fonction principale
• entier n• lire n• hanoi(n,1,2,3)
• où hanoi satisfait le prototype
• hanoi(entier, entier, entier, entier)
Djamal Rebaïne 35
• Supposons qu’on sache comment déplacer les (n-1) derniers disques de la tour 1 vers la tour 2, en utilisant la tour 3.
• déplacer le disque restant de la tour 1 vers la tour 2
• déplacer maintenant les (n-1) disques de la tour 3 vers la tour 2, en s’aidant de la tour 1.
Djamal Rebaïne 36
Fonction hanoi
Entête: hanoi(entier n, entier i, entier j, entier k)(Affiche les instructions pour déplacer n disques
de la tige i vers la tige k)Corps: si (n > 0) { hanoi(n-1, i, k, j)
écrire "Déplacer i vers k);hanoi(n-1, j, i, k)
}
Djamal Rebaïne 37
• #include <iostream.h>
•
• void hanoi (int,int,int,int)
• void hanoi(int n,int i,int j,int k)
• {
• if (n>0)
• {
• hanoi(n-1,i,k,j);
• cout <<“déplacer le disque de haut de la tour<<i<<“ à la tour “<<k;
• hanoi(n-1,j,k,i);
• }
• main()
• {
• int n;
• cin>>n;
• hanoi(n,1,2,3);
• }
Djamal Rebaïne 38
Exemple avec n = 4 disques
• On obtient la série d’affichages suivants:• Déplacer le disque de haut de la tour 1 à la tour 2• Déplacer le disque de haut de la tour 1 à la tour 3• Déplacer le disque de haut de la tour 2 à la tour 3• Déplacer le disque de haut de la tour 1 à la tour 2• Déplacer le disque de haut de la tour 3 à la tour 1• Déplacer le disque de haut de la tour 3 à la tour 2• Déplacer le disque de haut de la tour 1 à la tour 2• Déplacer le disque de haut de la tour 1 à la tour 3• Déplacer le disque de haut de la tour 2 à la tour 3• Déplacer le disque de haut de la tour 2 à la tour 1• Déplacer le disque de haut de la tour 3 à la tour 1• Déplacer le disque de haut de la tour 2 à la tour 3• Déplacer le disque de haut de la tour 1 à la tour 2• Déplacer le disque de haut de la tour 1 à la tour 3• Déplacer le disque de haut de la tour 2 à la tour 3
Djamal Rebaïne 39
Voyons cela de plus près
Djamal Rebaïne 40
Pas-à-pas avec n=3
entier n nfactlire n si (n < 0) alors écrire “entrée négative: ” nsinon hanoi(n,1,2,3);
entier n
.
.
.
.
.
.
n
Djamal Rebaïne 41
entier nlire n nfactsi (n < 0) alors écrire “entrée négative: ” nsinon hanoi(n,1,2,3)
lire n
.
.
.
.
.
.
3n
Djamal Rebaïne 42
entier n lire nsi (n < 0) alors écrire “entrée négative: ” nsinon hanoi(n,1,2,3)
.
.
.
.
.
.
4n entier
Djamal Rebaïne 43
entier n nfactlire nsi (n < 0) alors écrire “entrée négative: ” nsinon hanoi(3,1,2,3)
1
.
.
.
.
.
.
3
2
3
3
n entier
entiern
entier
si (n 0) retourner hanoi(2,3,2,1)hanoi( , , , )
Djamal Rebaïne 44
TITLE hanoi-program
SPILE SEGMENT STACK
DW 100 DUP(?)
SPILE ENDS
SDATA SEGMENT
n dw 6
SDATA ENDS
SCODE SEGMENT
ASSUME CS:SCODE,DS:SDATA
DEBUT:
mov ax,sdata
mov ds,ax
xor ax,ax
xor cx,cx
xor dx,dx
xor bx,bx
mov ax,n
mov cl,1; la tour i
mov ch,2; la tour j
mov dh,3; la tour k
call hanoi
sortie:
MOV AX,4C00H
INT 21H
Djamal Rebaïne 45
hanoi proc near
si1:
cmp ax, 0 ; comparer ax avec 0
ja else ; si n> 0, continuer
ret
else:
dec ax ; décrémenter ax de 1 c'est-à-dire égal à n-1
mov temp, ch
mov ch, dh
mov dh, temp
push cl ; sauvegarder en premier le i
push dh ; sauvegarder en deuxième le k
push ch ; sauvegarder en troisième le j
push ax ; mettre n -1 sur la pile
call hanoi ; appel à hanoi
; passer au déplacement des tours
mov al, cl ; mettre le i dans al
mov ah,2
int 21h
mov al, 32 ; mettre un blanc dans al
mov ah,2
int 21h
mov al, dl ; mettre le k dans al
mov ah,2
int 21h
Djamal Rebaïne 46
Djamal Rebaïne 47
pop ax ; ax = n-1
pop dh
pop ch
pop cl
push ch
push cl
push dh
call hanoi
ret
Hanoi endp
SCODE ENDS
END DEBUT