Algorithmes et fonctions

Le pseudo-code permet d'écrire des algorithmes de façon claire et sans ambiguïtés.

Algorithme

Définition

Un algorithme est une suite d'instructions de pseudo-code qui, a partir de paramètres d'entrées de type déterminé, rend une sortie de type déterminé.

Considérons par exemple la description de l'algorithme de recherche d'un élément dans une liste :

Nom : recherche
Entrées :
    T : un tableau d'entiers
    x : un entier
Sortie :
    un booléen
Programme :
    parcourir chaque élément de t jusqu'à trouver un élément dont la valeur est égale à la valeur de x.
    Si on trouve un tel élément, rendre "Vrai"
    Sinon rendre "Faux"

En pseudo-code, cela va donner ça :

algorithme recherche(T: [entier],
                     x: entier     # entier recherché dans t
                    )  booléen:   # Vrai si x est dans t

    e := entier
    pour chaque e de T:
        si e == x:
            rendre Vrai
    rendre Faux

Le programme est un bloc. La definition du bloc (jusqu'aux :) est constitué :

  1. du mot-clé algorithme qui détermine la nature du bloc
  2. suit le du nom du programme
  3. puis ses paramètres d'entrées entre parenthèses. Chaque paramètre est décrit par son nom suivit de son type
  4. enfin, le type de sortie de l'algorithme qu'on fait précéder d'une flèche.

Si on a besoin d'information supplémentaire pour qu'un lecteur puisse mieux comprendre le pseudo-code on peut ajouter des commentaires en les faisant commencer par un #. Ne mettez pas trop de commentaires, normalement le pseudo-code et le nom des variables doit suffire. On a ici juste décrit ce que fait l'algorithme avec ses paramètres d'entrées.

La description des types de paramètres est reprise du format python : https://docs.python.org/fr/3.13/library/typing.html

Terminons par un petit exercice :

Adaptez le pseudo code de l'algorithme recherche(T: [entier], x: entier) → booléen précédent pour créer l'algorithme :

nombre(T: [entier], x: entier)  entier

Cet algorithme rend le nombre de fois où x est présent dans T

corrigé

algorithme nombre(T: [entier], x: entier)  entier:
    nb := entier
    nb  0

    e := entier
    pour chaque e de T:
        si e == x:
            nb  nb + 1
    rendre nb

Fonctions

Dans un programme, de nombreuses phases sont répétées à divers endroits du code (sommer ou multiplier des vecteurs 3D dans un moteur physique par exemple). Pour éviter de devoir replacer toutes ces instructions à chaque fois on définis des sous-programmes réutilisables à volonté, appelés fonctions.

Définition

Une fonction est un programme. Elle a ainsi :

  • un nom
  • des paramètres d'entrée
  • une sortie
  • des instructions, appelées corps de la fonction

Une fois définie, on peut l'appeler comme une instruction (sa sortie est affectée à la variable sortie dans l'exemple ci-après) :

sortie  nom_fonction(entrée_1, ..., entrée_n)

Appels de fonctions

On peut définir des fonctions puis les utiliser ensuite comme dans tout langage de programmation. Considérons l'algorithme de recherche :

algorithme recherche(t: [entier],
                     x: entier
                    )  booléen:

    e := entier
    pour chaque e de t:
        si e == x:
            rendre Vrai
    rendre Faux

On peut utiliser le pseudo code de nom recherche dans d'autres pseudo-code comme une fonction. Par exemple :


t := [entier]{longueur: 3}
t  [1, 2, 6]

trouve := booléen
trouve  recherche(t, 6)
affiche à l'écran trouve

Est un pseudo-code valide puisque recherche est bien défini et utilisé correctement (le type de ses paramètres est correct).

À retenir

  • Les différentes exécutions de fonctions au sein d'un même algorithmes ne partagent pas leurs variables.
  • Les paramètres sont des variables qui sont initialisées au début de l'exécution de la fonction.
  • Seuls les objets peuvent être transmis.

Dans l'exemple précédent, la variable e définie dans la fonction recherche n'est pas visible depuis l'algorithme. En revanche, l'objet booléen de retour est lui transmis à l'algorithme via l'instruction rendre.

Pseudo-code avec fonctions

On peut aussi directement coder des fonctions dans un pseudo-code. Par exemple :

fonction recherche(t: [entier],
                   x: entier
                  )  booléen:

    e := entier
    pour chaque e de t:
        si e == x:
            rendre Vrai
    rendre Faux

algorithme exorcisme(t: [entier]
                    )  chaîne:

    si recherche(t, 666):
        rendre "Aspergez votre ordinateur d'eau bénite. Vite !"
    sinon:
        rendre "Tout va bien, le tableau n'est pas possédé. Ouf."

Que va afficher l'exécution de l'algorithme suivant :

fonction affiche_double(e: entier) :

    x := entier
    x  2 * e
    affiche x

algorithme calculatrice() :

    x := entier

    x  demande un entier à l'utilisateur
    affiche_double(x)
    affiche x

corrigé

L'entier x de la fonction est indépendant de l'entier x défini dans l'algorithme. L'exécution de l'algorithme affichera alors :

  1. le double de l'entier demandé à l'utilisateur : exécution de la ligne 5
  2. l'entier demandé à l'utilisateur : exécution de la ligne 13

Tableaux et fonctions

À retenir

Les objets sont communs à toutes les exécutions d'un même algorithmes. Ils peuvent passer d'une fonction à une autre via les variables.

Par exemple :

fonction modif(U: [entier]) :

    U[2]  U[0] + U[1]

algorithme tableau() :

    T := [entier]{longueur: 3}

    T[0]  1
    T[1]  2
    T[2]  0
    affiche T[2]
    modif(T)
    affiche T[2]

Va afficher 0 puis 3. En effet :

Les tableaux sont les seuls objets défini en pseudo-code qui peuvent être modifiés, ce n'est pas le cas ni des 5 types basiques ni des chaînes.

À retenir

Vérifiez toujours très soigneusement vos algorithmes lorsque vous créez des tableau que vous passez en paramètres de fonctions. Ils peuvent être modifiés par cette fonction !

Type d'un algorithme ou d'une fonction

Lorsque l'on défini un algorithme ou un pseudo-code on explicite le type des objets en entrées et en sortie :

Définition

Une signature de fonction associe :

  • son nom
  • le type de chacun de ses paramètres
  • le type de sortie

On le représente ainsi :

nom_de_l_algorithme(type_premier_paramètre, ..., type_dernier_paramètre)  type_de_sortie

Ou, lorsque le nom des paramètre peut-être utile on pourra les ajouter ainsi :

nom_de_l_algorithme(nom_premier_paramètre: type_premier_paramètre, ..., nom_premier_paramètre: type_dernier_paramètre)  type_de_sortie

Définition

Le type d'un algorithme est sa signature sans son nom.

Par exemple pour l'algorithme recherche :

Lorsque le nom des paramètres est significatif, on les ajoutera à la signature. On écrira par exemple division(dividende: réel, diviseur: réel) → réel plutôt que division(réel, réel) → réel qui ne nous permet pas directement d'utiliser la fonction.

Associer un type à une fonction permet lui permet d'être associée à un nom comme tout autre objet. Par exemple, en supposant que la fonction recherche soit définie :

f := ([entier], entier)  booléen

f  recherche
affiche f([1, 2, 6], 6)

Ne confondez pas nom qui est l'algorithme et nom(a, b) qui est le résultat de son exécution avec les paramètres a et b.

Récursivité

Le fait que les variables et les noms définies dans les fonctions restent dans le cadre de la fonction actuellement exécuté nous donnent accès à la récursivité : Il suffit que notre pseudo-code s'appelle lui-même comme une fonction.

Attention aux conditions d'arrêts pour garantir qu'une fonction ne s'appelle pas indéfiniment.

Par exemple l'algorithme suivant est une implémentation récursive de l'algorithme recherche :

algorithme recherche(T: [entier],
                     x: entier     # entier recherché dans t
                    )  booléen:   # Vrai si x est dans t

    si T.longueur == 0:
        rendre Faux
    sinon si T[0] == x:
        rendre Vrai
    sinon:
        rendre recherche(T[1:], x)