Corrigé

Algorithme

Le successeur d'un élément est l'élément plus 1. La somme du dernier bit de n avec 1 fait alors soit :

Si la somme vaut 10, cela revient à réitérer le processus sur l'avant dernier bit.

Donc on commence par regarder le bit n[i] en commençant par le dernier. S'il vaut :

Complexité

La complexité va dépendre du nombre d'éléments dans la liste en entré. Notons $N = len(n)$.

On remarque (facilement) que cette complexité vaut $C(N) = K \cdot \mathcal{O}(1)$ où $K$ est le nombre de fois où l'on rentre dans la boucle.

Complexité en moyenne

Séparons les $2^N$ nombres possibles en classes selon le nombre d'itérations dans la boucle :

Le nombre moyen d'itérations dans la boucle vaut alors :

$$ W_\text{moy}(N) = \mathcal{O}(1) \cdot \sum_{i=0}^{N-1} i \cdot \frac{1}{2^{i+1}} $$

Vérification expérimentale

def successeur(n):
    K = 0

    while i >= 0 and (n[i] == 1):
        K += 1

        n[i] = 0
        i -= 1

    if i >= 0:
        n[i] = 1

    return K


def tous(N):

    n = [0] * N
    total = 0
    for i in range(2**N):
        total += successeur(n)
        print(n)

    return total / 2 ** N


x = tous(5)
print(x)

Récursif

Preuve

Chaque récursion crée une liste avec un élément supplémentaire, cette élément valant d'abord 0, puis 1 lorsque l'on reviendra à cette fonction après la récursion.

Complexité en mémoire

La complexité en mémoire est de $N^2$, car chaque récursion (il y en a $N$ simultanées au maximum) garde en mémoire une liste d'au plus $N$ éléments.

Généralisation

En utilisant la version récursive, il suffit de change le 2 en 6 à la ligne 5.