Récursivité

Download Report

Transcript Récursivité

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
1
Djamal Rebaïne
2
Un exemple
- (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
Djamal Rebaïne
3
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
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 3
appels à monter marche()
Djamal Rebaïne
5
Recette de récursivité
• 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 obtenus pour P1, P2,
…, pour obtenir la solution pour avoir la
solution au problème de départ.
Djamal Rebaïne
6
Fonctionnement d’une fonction
ré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
7
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
8
•
•
•
•
•
•
•
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
9
Fonction factoriel
int factoriel(entier n)
{
si (n < 1) retourner 1
retourner n * factoriel(n-1)
}
Djamal Rebaïne
10
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.
Djamal Rebaïne
11
Cela se traduit par le programme assembleur suivant
TITLE factoriel
PILE segment stack
dw 100 dup(?)
Basdepile equ this word
PILE ends
Data segment
N dw 4
fact dw ?
Data ends
Code 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 Rebaine
12
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édure
code ends
end debut ; fin du programme code
Djamal Rebaïne
13
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 word
PILE ends
Data segment
N dw 12
som dw ?
Data ends
Code 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
14
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
15
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
16
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
17
• Fonction principale
• ecrire “introdroduire la chaîne: ”
• inverser
Djamal Rebaïne
18
Fonction factoriel
Entête:
entier factoriel(entier n)
Corps:
lire car;
si car <> `.`
inverser;
afficher car;
Djamal Rebaïne
19
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
20
TITLE INVERSER-CHAINE
affiche macro chaine ;
mov dx,offset chaine ;
mov ah, 09h ;
int 21h
endm
PILE segment stack
dw 100 dup(?)
Basdepile equ this word
PILE ends
Data segment
Chaine db ‘introduire votre chaine’, 10,13, ‘$’
Data ends
Code 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
Affich chaine
call inverser; APPEL DE LA FONCTION INVERSER
Fin: mov AX,4c00h
int 21h
Djamal Rebaïne
21
inverser Proc near; les appels récursifs sont gérés exclusivement par la pile.
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
inverser
Depiler: POP AX
mov AH,2
int 21
ret
inverser; fin de la procédure
code ends; fin du programme principal
end debut
Djamal Rebaïne
22
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 depiler
ret
inverser; fin de la procédure
code ends; fin du programme principal
end debut
Djamal Rebaïne
23
• Rechercher l’élément C dans un tableau
trié dans l’ordre croissant.
…………… C?
L
…..
milieu
Djamal Rebaïne
A
u
24
• 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
25
TITLE dichotomique
PILE segment stack
dw 100 dup(?)
Basdepile equ this word
PILE ends
Data segment
tableau db 1, 4, 8, 10, 18
Donnee db 18
Data ends
Code 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
Lea SI, tableau;
mov BX, SI
Add BX, tableau[1] ; adresse du dernier élément du tableau
push BX
push SI
call dichoto
Fin: mov AX,4c00h
int 21h
Djamal Rebaïne
26
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 fin
Autreappel: push SI
push BX
dichoto
Fin: ret
code ends
end debut
Djamal Rebaïne
27
Les nombres de Fibonacci
• Question: Écrire un programme qui
nème
calcule le
nombre de Fibonacci
défini comme suit:
Fn  Fn1  Fn2 ; si n  1
F0  0; F1  1
Djamal Rebaïne
28
TITLE fibonacci
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 bx,bx
mov ax,n
call fibo
mov dl,al
add dl,30h
mov ah,2
int 21h
sortie:
MOV AX,4C00H
INT 21H
Djamal Rebaïne
29
Fibo proc
si1:
cmp ax, 1
; comparer ax avec 1
ja else
; si n<= 1, retourner 1
mov ax, 1
; mettre 1 dans ax
ret
else:
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)
ret
Fibo endp
SCODE ENDS
END DEBUT
Djamal Rebaïne
30
Les tours de Hanoï
http://www.multimania.com/fmaire/jeux/hanoi/hanoi.html
http://members.aa.net/~wgf/Hanoi/Hanoi.html
Djamal Rebaïne
31
• 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.
Djamal Rebaïne
32
• 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
• Fonction principale
• entier n
• lire n
• hanoi(n,1,2,3)
• où hanoi satisfait le prototype
•
hanoi(entier, entier, entier, entier)
Djamal Rebaïne
34
• 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
35
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
36
•
•
•
#include <iostream.h>
•
•
•
•
•
•
•
•
•
•
•
•
•
•
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);
}
void hanoi (int,int,int,int)
Djamal Rebaïne
37
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
38
Voyons cela de plus près
Djamal Rebaïne
39
Pas-à-pas avec n=3
n
entier n nfact
lire n
si (n < 0) alors écrire “entrée négative: ” n
sinon
hanoi(n,1,2,3);
.
.
.
Djamal Rebaïne
.
.
.
40
n
3
entier n
lire n nfact
si (n < 0) alors écrire “entrée négative: ” n
sinon
hanoi(n,1,2,3)
.
.
.
Djamal Rebaïne
.
.
.
41
entier n
lire n
si (n < 0) alors écrire “entrée négative: ” n
sinon
hanoi(n,1,2,3)
n
.
.
.
Djamal Rebaïne
entier
4
.
.
.
42
entier n nfact
lire n
si (n < 0) alors écrire “entrée négative: ” n
sinon
hanoi(3,1,2,3)
n
3
entier
n
3
entier
1
entier
2
3
si (n  0)
retourner
hanoi(2,3,2,1)
hanoi( , , , )
.
.
.
Djamal Rebaïne
.
.
.
43
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
44
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
Djamal Rebaïne
45
; 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
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
Djamal Rebaïne
47