I. Introduction ` a la r´ ecursivit´ e
1 - Pr´ esentation
En informatique, les fonctions r´ecursives sont des fonctions dont le calcul n´ecessite d’invoquer la fonction elle-mˆeme.
D´ efinition :
Cela permet de traduire informatiquement l’id´ee de r´ecurrence en math´ematiques.
Par exemple, la d´efinition par r´ecurrence de la factorielle est :
n! = 1 sin= 0 n×(n−1)! sinon.
Exemple 1 :
´Ecrire une fonction r´ecursive, c’est ´ecrire :
• Une condition d’arrˆet , tr`es importante, correspondant `a l’initialisation de la r´ecurrence,
• Un ou plusieurs appels r´ecursifs, correspondant `a l’h´er´edit´e.
D´ efinition :
Ecriture r´ecursive de la fonction factorielle :
Exemple 2 :
1 d e f f a c t ( n ):
2 " R e n v o i e la f a c t o r i e l l e de n " " "
3 if n == 0:
4 r e t u r n 1
5 e l s e:
6 r e t u r n n * f a c t ( n -1)
2 - Pile de r´ ecursion
L’interpr´eteur g`ere une pile dite de r´ecursion pour les appels successifs puis les calculs
`a effectuer.
Pour sch´ematiser, l’appel de fact(4) correspond `a la situation d´ecrite sur la figure suivante. La commande fact(4) demande l’ex´ecution de fact(3) puis defact(2), puis defact(1), puis defact(0)qui renvoie la valeur 1. L’ex´ecution du programme impose alors le calcul `a partir du haut de la pile d’information `a traiter.
Figure 1: Exemple de pile de r´ecursion
REVITRON.FREE.FR II EXEMPLES D’ALGORITHMES
En python, la pile de r´ecursion est limit´ee `a 1 000 appels environ. Il est possible de modifier cette limite : import sys
sys.setrecursionlimit( nb )
Remarque 1 :
Ecrire une fonction r´ecursive donnant le nieme, terme de la suite de H´eron d´efinie avecu0= 1 et
un+1=u2n+ 2 2un
Exemple 3 :
Solution 1 Il existe plusieurs solutions :
1 def H e r o n 1 ( n ):
2 " r e t o u r n e le t e r m e d ’ i n d i c e n de la s u i t e de H e r o n "
3 if n == 0: r e t u r n 1
4 e l s e:
5 u = H e r o n 1 ( n - 1)
6 r e t u r n ( u **2 + 2) / (2* u )
7 . .. .
8 def H e r o n 2 ( n , u ):
9 """
10 n , u : Int , f l o a t
11 r e t o u r u_n par H e r o n
12 """
13 if n == 0:
14 r e t u r n u
15 u = ( u **2 + 2) / (2* u )
16 r e t u r n h e r o n ( n -1 , u ) 17 ...
18 def H e r o n 3 ( n , u ):
19 if n == 0: r e t u r n u
20 r e t u r n h e r o n ( n -1 , u )/2 + 1 / h e r o n ( n -1 , u )
Il existe des probl`emes Python due `a la programmation objet de python. Les listes utilisent ´egalement la r´ecursivit´e et des modification de listes peuvent conduire `a des r´esultats surprenants au premier abord :
1 > > > L = [1 ,2]
2 > > > L [0] = L 3 > > > L 4 [[...] , 2]
5 > > > L [0]
6 [[...] , 2]
7 > > > L [ 0 ] [ 0 ] 8 [[...] , 2]
II. Exemples d’Algorithmes
1 - Parcours d’une liste sans forme...
Dans certains cas, l’´ecriture r´ecursive d’un algorithme est beaucoup plus facile que son homologue non-r´ecursif :
D’apr`es Centrale 2019
On d´esire fare la somme de d’´el´ements dans une liste d’entier dont les
´el´ements sont des listes de diff´erentes tailles : L = [1,5,[23,12],[0],[
[ 0,3] , [1] , 4] ] . On utilisera la fonction isinstance(a,int) qui renvoie Truesiaest un entier etFalsesinon
Exemple 4 :
Solution 2
1 def s o m m e ( L ):
2 if i s i n s t a n c e( L ,int):
3 r e t u r n L
4 e l s e :
5 s = 0
6 for x in L :
7 s += s o m m e ( x )
8 r e t u r n s
On peut aussi utiliser la notion de pile pour d´epiler la liste et en faire une liste
”plate”.
1 def s o m m e ( L ):
2 L _ f l a t = []
3 w h i l e len( L ) >0:
4 elt = L . pop ()
5 if i s i n s t a n c e( elt ,int):
6 L _ f l a t . a p p e n d ( elt )
7 e l s e :
8 for x in elt :
9 L . a p p e n d ( x )
10 #calcul de la somme
11 s = 0
12 for x in L _ f l a t :
13 s += x
14 r e t u r n s
2 - Une suite d´ efinie par r´ ecurrence
D’apr`es Concours blanc 2022 On note S(n, k) la suite d´efinie par :
• S(0,0) = 1
• ∀n∈N∗, S(n,0) = S(0,n) = 0
• ∀(n,k)∈N∗×N∗; S(n,k) = S(n−1,k−1) +kS(n−1,k)
On v´erifiera la fonction en ´etablissant le tableau de valeur suivant : k= 0 k= 1 k= 2 k= 3 k= 4 k= 5 k= 6
n=0 1 0 0 0 0 0 0
n=1 0 1 0 0 0 0 0
n=2 0 1 1 0 0 0 0
n=3 0 1 3 1 0 0 0
n=4 0 1 7 6 1 0 0
Exemple 5 :
3 - Recherche de z´ ero d’une fonction par dichotomie
a) Ecriture non r´´ ecursive
1 d e f d i c h o ( f , a , b , e r r e u r ):
2 ’ ’ ’
3 R e c h e r c h e de f ( x )=0 par d i c h o t o m i e 4 f : f u n c t i o n
5 a , b , e r r r e u r : f l o a t
6 r e t o u r : m e i l l e u r a p p r o x de x a e r r e u r p r e s
7 ’ ’ ’
8 w h i l e ( b - a ) > e r r e u r :
9 c =( a + b )/2
10 if f ( a )* f ( c ) <0:
11 b = c
12 e l s e :
13 a = c
14 r e t u r n a
b) Ecriture r´´ ecursive
Proposer une fonction dicho(f,a,b,erreur)permettant d’obtenir z´ero de f de fa¸con r´ecursive par dichotomie. On testera le r´esultat pour une fonction f(x) =x2−2 aveca= 1 etb= 2. On rappelle que√
2≈1,44.
Exemple 6 :
Solution 3
1 def d i c h o ( f , a , b , e r r e u r ):
2 """
3 f : f o n c t i o n
4 a , b : f l o a t
5 e r r e u r : f l o a t
6 R e t o u r : x dans [ a , b ] a n n u l a n t f a e r r e u r pr es 7 """
8 if b - a < e r r e u r :
9 r e t u r n a
10 c = ( a + b ) / 2
11 if f ( a )* f ( c ) <0:
12 r e t u r n d i c h o ( f , a , c , e r r e u r )
13 e l s e :
14 r e t u r n d i c h o ( f , c , b , e r r e u r )
4 - Recherche de z´ ero par m´ ethode de Newton
a) Ecriture non r´´ ecursive
REVITRON.FREE.FR II EXEMPLES D’ALGORITHMES
1 d e f N e w t o n ( f , fprime , x , e r r e u r ):
2 ’ ’ ’
3 R e c h e r c h e de f ( x )=0 par N e w t o n 4 f , f p r i m e : f u n c t i o n
5 x , e r r r e u r : f l o a t
6 r e t o u r : m e i l l e u r a p p r o x de f ( x )=0 a e r r e u r p r e s
7 ’ ’ ’
8
9 w h i l e a b s( f ( x )/ f p r i m e ( x )) > e r r e u r : 10 x -= f ( x )/ f p r i m e ( x )
11 r e t u r n x
Ce code est beaucoup plus performant que la m´ethode par dichotomie mais la con- vergence n’est pas assur´ee. En particulier, sif′(x) = 0, la valeur dexdiverge.
b) Ecriture r´´ ecursive
Ecrire une fonctionNewton(f,fprim,x0,erreur)permettant d’obtenir z´ero de f de fa¸con r´ecursive par la m´ethode de Newton. On testera le r´esultat pour une fonction f(x) = x2−2 avec a = 1 et b = 2. On rappelle que
√2≈1,44.
Exemple 7 :
Solution 4
1 def N e w o n ( f , fprim , x , e r r e u r ):
2 """
3 f , f p r i m : f o n c t i o n s
4 x : f l o a t
5 e r r e u r : f l o a t
6 R e t o u r : x a n n u l a n t f a e r r e u r p r e s 7 """
8 if abs( f ( x )) < e r r e u r : r e t u r n x
9 e l s e:
10 x = x - f ( x )/ f _ p r i m ( x )
11 r e t u r n N e w o n ( f , fprim , x , e r r e u r )
5 - Recherche d’un indice dans une liste tri´ ee
Proposer deux fonctionsindice NR(x,Ltri)etindice R(x,Ltri,a,b)per- mettant d’obtenir la position dexdans une liste tri´eeLtri. Les param`etres aet bsont des curseurs pointant intialement vers 0 etlen(Ltri)-1. On testera la fonction avec la position de l’´el´ement 4 dans la liste L = [0,1,3,4,8,10] .
Exemple 8 :
Solution 5
1 def i n d i c e _ N R ( x , L _ t r i ):
2 a , b = 0 , len( L _ t r i ) -1 3 w h i l e b != a :
4 m = ( b + a ) // 2
5 if L _ t r i [ m ]== x :r e t u r n m 6 e l i f x > L _ t r i [ m ]: a = m
7 e l s e : b = m
8 r e t u r n a
1 def i n d i c e _ R ( x , L_tri , a , b ):
2 if L _ t r i [ a ] == x : r e t u r n a 3 e l i f L _ t r i [ b ] == x : r e t u r n b
4 e l s e :
5 m = ( a + b ) // 2
6 if L _ t r i [ m ] < x :
7 r e t u r n i n d i c e _ R ( x , L_tri , m , b )
8 e l s e :
9 r e t u r n i n d i c e _ R ( x , L_tri , a , m )
6 - (Facultatif) Maximum d’une liste
´Ecrire les fonctions de mani`eres r´ecursives suivantes : Max(L) permettant d’obtenir le maximum d’une liste de fa¸con r´ecursive
Exemple 9 :
Solution 6
1 def max( L ):
2 """
3 L : L is t n u m e r i q u e
4 r e t o u r max de L
5 """
6 if len( L ) ==1 : r e t u r n L [0]
7 x1 = L [ -1]
8 x2 = L [ -2]
9 if x1 < x2 :
10 r e t u r n max( L [: -2]+[ x2 ])
11 e l s e:
12 r e t u r n max( L [: -2]+[ x1 ])
13 p r i n t(" Max = ",max( L ))
ou encore :
1 def max( L ):
2 if len( L ) == 1:
3 r e t u r n L [0]
4 e l s e:
5 a = L . pop ()
6 m = m a x1 ( L )
7 L . a p p e n d ( a ) # C’est mieux si L reste intacte !
8 if a > m :
9 r e t u r n a
10 e l s e:
11 r e t u r n m
III. Applications classiques en math´ ematiques
1 - Coefficients binomiaux
On peut vouloir calculer nken utilisant la formule du triangle de Pascal
n
k
=n−1 k−1
+n−1 k
1. Proposer une fonction binom(k, n) utilisant un algorithme r´ecursif
´evaluant nk.
2. Montrer que l’algorithme propos´e est inutilisable pour de grandes valeurs de n.
Exemple 10 :
Solution 7 Cela donne la fonction na¨ıve :
1 def b i n o m ( k , n ):
2 if k < 0 or k > n :
3 r e t u r n 0
4 if k == 0 or k == n :
5 r e t u r n 1
6 r e t u r n b i n o m ( k - 1 , n - 1) + b i n o m ( k , n - 1)
Si l’on ´evalue la complexit´e, le double de la fonction binom conduit `a une complexit´e de la mˆeme forme que les coefficients binomiaux :
C(k,n) = C(k−1,n−1) + C(k,n−1) + 1
soitC(k,n)∼ nk .
REVITRON.FREE.FR IV CALCUL DE COMPLEXIT ´E
IV. Calcul de complexit´ e
1 - Rappels sur la complexit´ e
´Evaluer la complexit´e en temps d’une fonction consiste `a donner un ordre de grandeur du nombre d’op´erations ´el´ementaires effectu´ees lors de l’ex´ecution de cette fonction. On admettra comme op´eration ´el´ementaire une op´eration arithm´etique, une affectation, une comparaison (´evaluation d’une expression bool´eenne), l’affichage d’un r´esultat, l’acc`es `a un ´el´ement d’une liste, l’ajout ou la suppression d’un ´el´ement `a une liste, le calcul de la longueur d’une liste.
Soitf une fonction admettant un entier ncomme param`etre. On note C(n) la complexit´e en temps de la fonction f par rapport `a n. Soit ( n)n2N une suite de r´eels positifs. On dit que la complexit´e C(n) de f est en O(γ(n)) s’il existe (a;b) etn0 tel que
∀n⩾n0, a×γ(n)⩽C(n)⩽b×γ(n)
D´ efinition :
On parle de complexit´e :
• en temps constant si C(n) = O(1) ;
• logarithmique si C(n) = O(ln(n)) ;
• lin´eaire si C(n) = O(n) ;
• quadratique si C(n) = O(n2) ;
• polynomiale de degr´epsi C(n) = O(np) ;
• exponentielle s’il existeatel que C(n) = O(an).
D´ efinition :
Si une op´eration ´el´em´entaire s’effectue en 1mus, pour 100 op´erations le tableau suivant donne une id´ee des temps de calcul
Complexit´e O(n) O(n2) O(2n) temps 0,1 ms 0,01 s 1,3.1030s Pour conversion : 1030s= 4.1022ans
a) Pour des fonctions non-r´ecursives
Pour des fonctions non-r´ecursives le calcul de complexit´e s’effectue en comptant le nombre d’op´erations effectu´ees :
• pour une boucle, la complexit´e est en O(n), ex :
1 d e f m a x( L ):
2 m = L [0]
3 f o r x in L :
4 if x > m :
5 m = x
6 r e t u r n m
• pour deux boucles imbriqu´ees, elle devient en O(n2).
1 d e f m a x _ 2 D ( t a b l e a u ):
2 m , n = t a b l e a u . s h a p e 3 m a x= L [0 ,0]
4 f o r i in r a n g e(1 , m ):
5 f o r j in r a n g e(1 , n )
6 if x > m :
7 m a x = x
8 r e t u r n m a x
b) Calcul de factoriel
La complexit´e temporelle s’obtient sous forme de suite r´ecurrente. L’obtention de la suite s’´ecrit en ´evaluant le nombre d’appel de la fonction r´ecursive et le nombre d’op´eration effectu´e dans la fonction :
1 d e f f a c t ( n ):
2 " R e n v o i e la f a c t o r i e l l e de n " " "
3 if n == 0:
4 r e t u r n 1
5 e l s e:
6 r e t u r n n * f a c t ( n -1)
La fonction est appel´ee une seule fois : fact(n-1), il y a une op´eration (*), on obtient :
T(n) = 1×T(n−1) + 1
. On reconnaˆıt l’´ecriture d’une suite arithm´etique, on en d´eduit que
T(n) =a×n+b= O(n) c) Suite de h´eron
1 d e f H e r o n 1 ( n ):
2 " r e t o u r n e le t e r m e d ’ i n d i c e n de la s u i t e de H e r o n "
3 if n == 0: r e t u r n 1
4 e l s e:
5 u = H e r o n 1 ( n - 1)
6 r e t u r n ( u **2 + 2) / (2* u )
Notonsαle nombre d’op´eration ´el´ementaires. La fonction est appel´ee une seule fois, la formule de r´ecurrence est ici :
T(n) = 1×T(n−1) +α On obtient une suite arithm´etique de raison 1. Ainsi :
T(n) = O(n) Consid´erons maitenant le code suivant :
1 d e f h e r o n ( n , u ):
2 if n = = 0 : r e t u r n u
3 r e t u r n h e r o n ( n -1 , u )/2 + 1 / h e r o n ( n -1 , u )
Notonsαle nombre d’op´eration ´el´ementaires, la formule de r´ecurrence est ici : T(n) = 2×T(n−1) +α
Le facteur 2 provient du double appel de la fonction heron. On obtient une suite arithm´etico-g´eom´etrique de raison 2. Ainsi :
T(n) = O(2n) La complexit´e de la fonction ´ecrite est exponentielle !