Aller au contenu

Appels récursifs multiples

Sans atteindre la profondeur maximale de récursion, on peut écrire un programme très lent avec une méthode récursive naïve avec des appels multiples.

La fonction de Fibonacci

On considère la fonction naïve :

🐍 Script Python
def fib(n):
    if n < 2:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

Ici, fib est une fonction récursive avec appels multiples.

On peut construire à la main le tableau de valeurs

n 0 1 2 3 4 5 6 7 8 9 10
fib(n) 0 1 1 2 3 5 8 13 21 34 55

Mais observons comment fonctionne un script qui appelle fib(5)

Version dynamique⚠ site externe

On constate une profondeur d'appel faible 5, et de manière générale n. Pourtant, il y a de nombreux appels à f : ici \(15\).

On peut faire un script qui compte le nombre d'appels avec une astuce de POO (Programmation Orientée Objet) : une fonction est un objet, on lui donne un attribut compteur que l'on initialise avant utilisation.

🐍 Script Python
def fib(n):
    fib.compteur += 1 # à chaque utilisation de `fib`
    if n < 2:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

for n in range(10):
    fib.compteur = 0  # Initialisation du compteur
    fib(n)
    print(n, fib.compteur)


for n in [30, 35]:
    fib.compteur = 0
    fib(n)
    print(n, fib.compteur)

On obtient la suite des nombres de Leonardo1

n 0 1 2 3 4 5 6 7 8 9 10
leo(n) 1 1 3 5 9 15 25 41 67 109 177
  • Pour n = 30, on atteint \(2\,692\,537\) appels.
  • Pour n = 35, on atteint \(29\,860\,703\) appels, ce qui ralentit déjà un ordinateur.

On est pourtant loin d'une profondeur de 1000 !

Pour rendre le calcul de la fonction de Fibonacci moins naïf, on peut faire de la mémoïsation. On stocke dans un tableau ou un dictionnaire les résultats déjà connus en vue de leur réutilisation.

🐍 Script Python
fib_memo = {0: 0, 1: 1}

def fib(n):
    """Version récursive efficace"""
    if n not in fib_memo:
        fib_memo[n] = fib(n - 1) + fib(n - 2)

    return fib_memo[n]

Les tours de Hanoï

En guise d'exercice, après avoir résolu le problème des tours de Hanoï, déterminer le nombre de déplacements élémentaires en fonction du nombre initial de disques.