Récursivité

Cette page contient un ensemble de fonctions qu’il est possible de programmer de manière fonctionnelle pure, en utilisant des algorithmes récursifs. A chaque fois, on insiste sur la description formelle de la fonction à représenter, on discute les problèmes de terminaison, et de complexité.

1ère partie : Exponentiation

  • La version linéaire
def power_lin(a, n):
    if (n == 0):
        return 1
    else:
        return a * power_lin(a, n-1)
  • La version binaire
def power_bin(a, n):
    if (n == 0):
        return 1
    elif (n == 1):
        return a
    elif (n % 2 == 0):
        b = power_bin(a, n // 2)
        return b*b
    else:
        b = power_bin(a, n // 2)
        return a * b * b

2ème partie : PGCD

  • La version récursive
def pgcd_rec(a, b):
    if a == 0:
        return b
    elif a == b:
        return b
    elif a > b:
        return pgcd_rec(b, a)
    else:
        return pgcd_rec(b % a, a)
  • La version impérative (avec boucle for)
def pgcd_imp(a, b):
    if a > b:
        a, b = b, a
    while (a != 0) and (a != b) :
        a, b = b % a, a
    return b
  • La page Rosetta Code contenant un ensemble d’écritures différentes pour la fonction PGCD.

  • Un exemple de fonction pour tester les différentes fonctions de calcul de PGCD :

def test_pgcd(pgcd_fun):
    test_values = [
        ((0,0), 0),
        ((4,4), 4),
        ((4,0), 4),
        ((3,5), 1),
        ((5,3), 1),
        ((12,42), 6),
    ]
    for ((a,b), c) in test_values:
        assert(pgcd_fun(a,b) == c)

3ème partie : suite de Syracuse

def syra(n):
    if (n == 1):
        return 1
    elif (n % 2 == 0):
        return syra(n // 2)
    else:
        return syra(3*n + 1)
def flight(n):
    if (n == 1):
        return [1]
    elif (n % 2 == 0):
        return [n] + flight(n // 2)
    else:
        return [n] + flight(3*n + 1)
def flight_len(n):
    if (n == 1):
        return 1
    elif (n % 2 == 0):
        return 1 + flight_len(n // 2)
    else:
        return 1 + flight_len(3*n + 1)
def max_flight(flight_fun, n):
    max_s  = 1
    imax_s = 1
    for i in range(2, n+1):
        l = flight_fun(i)
        if (l > max_s):
            max_s  = l
            imax_s = i
    return imax_s

Une autre implémentation d’une fonction qui calcule la longueur d’un vol, avec mémoïsation des calculs : on garde les calculs déjà faits dans une variable (nommée ici mem). Dans l’exemple suivant, la fonction flight_mem renvoie une fonction. Et cette fonction permet de calculer plus rapidement les valeurs avec max_flight.

def flight_mem():
    mem = { 1: 1 }  # stores computed flight lengths
    def flight_rec(n):
        if n in mem:
            return mem[n]
        elif (n % 2 == 0):
            l = flight_rec(n // 2)
            mem[n] = l+1
            return l+1
        else:
            l = flight_rec(3*n + 1)
            mem[n] = l+1
            return l+1
    return flight_rec

Exemples d’utilisation des deux fonctions pour comparaison :

n = 6
f = flight_mem()
# Comparaison des temps de calcul de f et de flight_len :
print(max_flight(flight_len, 10**n))
print(max_flight(f, 10**n))

4ème partie : récursivité et listes

def search_rec(l, x):
    if (l == []):
        return False
    elif (l[0] == x):
        return True
    else:
        return search_rec(l[1:], x)
def search_for(l, x):
    for y in l:
        if (x == y):
            return True
    return False
def count_rec(l, x):
    if (l == []):
        return 0
    elif (l[0] == x):
        return 1 + count_rec(l[1:], x)
    else:
        return count_rec(l[1:], x)
def count_for(l, x):
    res = 0
    for y in l:
        if (y == x):
            res += 1
    return res