La récursivité

recurs.cpp


Aujourd'hui, pour compenser le gros cours de la semaine dernière, je vais vous parler d'une subtilité informatique qui permet de trouver, lorsqu'elle est bien utilisée, des solutions d'une grande élégance à un certain nombre de problèmes. Il s'agit du concept de la récursivité.

La récursivité est ce qui se passe quand une fonction s'appelle elle-même. En effet, cela est tout à fait possible. Voyons tout de suite un exemple, avec la fonction Fact() que nous avons vu la semaine précédente. A la différence près qu'alors, nous avions utilisé une boucle pour faire le produit de tous les entiers de 1 à n. Cette fois-ci, voici la nouvelle version :

int Fact(int n)
{

    if(n == 1)

      return 1;

    else

      return (n*Fact(n-1));

}

Prenons comme exemple Fact(4) :

Maintenant que la récursivité s'est arrêtée (c'était le dernier appel à la fonction Fact()), remontons la chaîne des valeurs de renvoi :

Et hop, on obtient le même résultat. Et en gros, ça nous a pris deux lignes, et aucun calcul. N'est-ce pas une solution plus élégante que d'utiliser une boucle et 2 variables ?

Voyons tout de suite un autre exemple. Vous vous souvenez tous que pour savoir si un nombre est divisible par 3, il faut faire la somme de ses chiffres, et voir si celle-ci est divisible par 3 ? On remarque alors qu'on revient au point de départ : on se retrouve avec un second nombre dont on veut savoir s'il est divisible par 3. On fait donc la somme de ses chiffres à lui, etc, etc... jusqu'à ce qu'on trouve un chiffre, qui sera alors 3, 6 ou 9. Alors, on sait que le nombre de départ est divisible par 3. Sans le savoir, déjà à l'époque, on appliquait le principe de la récursivité. Faisons une application directe de ceci, en oubliant un instant que l'opérateur modulo peut nous dire si un nombre est divisible par un autre.

Il nous faut évidemment une fonction pour faire la somme des chiffres d'un nombre. Ce sera notre fonction récursive : elle calculera le résultat, et si ce résultat n'est pas un chiffre, elle renverra la somme des chiffres du résultat... et on aura une belle récursivité !

#include <iostream.h>

int SommeChiffres(int n)
{

    if(n == 0) return 0; // Pour ce cas particulier où n == 0

    int total = 0;
    do {

      total += n%10; // Quel est le dernier chiffre?
      n /= 10; // Et on le supprime!

    } while(n != 0);

    if(total <= 9)

      return total; // C'est un chiffre!

    else

      return SommeChiffres(total); // C'est un nombre, on recommence

}

int main(void)
{

    int n = 0;

    cout << "Entrez le nombre à tester : ";
    cin >> n;
    int resultat = SommeChiffres(n);
    if((resultat == 0) ||(resultat == 3) || (resultat == 6) || (resultat == 9))

      cout << n << " est un multiple de 3!\n";

    return 0;

}

Cependant, faites attention : il faut une condition d'arrêt ! Sinon, la récursivité est infinie, et la fonction va se construire en mémoire jusqu'à ce qu'il n'y en ai plus, ce qui fera probablement planter votre programme (au bout d'un temps plutôt long). Dans le premier programme, la condition d'arrêt, c'est le if(n == 1). Dans le second, il s'agit de if(total <= 9).

La récursivité est relativement efficace en C++ car les appels de fonctions sont rapides. Cependant, si c'est l'une des techniques les plus élégantes de la programmation, ce n'est pas la plus efficace. Si vous recherchez la performance brute, utilisez plutôt une boucle.

Donc en gros :

  • Une fonction peut s'appeler elle-même.
  • Dans une récursivité, il faut une condition d'arrêt.

Cette fois-ci, il n'y a pas d'exercice. La récursivité est un concept un peu hardu la première fois. Je vous conseille donc de ne pas vous arracher les cheveux sur ce cours, mais plutôt d'y revenir un peu de temps en temps. C'est ainsi que vous comprendrez la récursivité, de manière toute naturelle.

Fin du premier chapitre

Ceci était donc de dernier cours du premier chapitre. Vous avez appris à utiliser des variables dans des calculs, à utiliser les structures de sélection, à utiliser les boucles et les fonctions... vous êtes maintenant un programmeur, prêt(e) à partir faire vos premiers petits programmes tout seul. Et c'est ce que je vous conseille de faire dans un premier temps, car il n'y a rien de tel que l'expérimentation pour se sentir à l'aise avec quelque chose.

Dans le second chapitre, nous aborderons des points un peu plus avancés de la programmation, avec l'accès aux fichiers, des structures de données, les pointeurs... bref, vous allez découvrir toute la puissance du C++. A la fin du second chapitre, nous ferons un petit programme entier, un carnet d'adresses, qui nous permettra d'illustrer tout ce que nous aurons vu à ce moment-là. Alors si jusqu'ici, ce cours vous a plu (ou plutôt, s'il ne vous a pas trop déplu :-), engagez-vous dans le chapitre 2, celui qui vous apprendra tous les bons trucs du C++.