Vous êtes sur la page 1sur 10

ALGORITHMES ET STRUCTURES DE DONNEES ELEMENTAIRES

(E.T. : 20heures, E.D. : 20 heures, E.P. : 18 heures)

1. ELEMENTS ELEMENTAIRES DES ALGORITHMES.


1.1. Les chaînes de caractères
1.2. Fonctions et variables entières
1.3. Itérations et conditions
1.4. Transmission des paramètres
1.5. Raisonnement par récurrence
2. VECTEURS
2.1. Introduction
2.2. Algorithmes traitant un seul vecteur
2.3. Tris d’un vecteur
2.4. Algorithmes de mise à jour d’un vecteur
3. FICHIERS
3.1. Définition et propriétés
3.2. Actions primitives d’accès
3.3. Algorithmes traitant un seul fichier
3.4. Algorithmes traitant plusieurs fichiers

1. ELEMENTS ELEMENTAIRES DES ALGORITHMES


Définition d’un algorithme : suite d’actions que devra effectuer un automate (ordinateur) pour arriver en
un temps fini, à un résultat déterminé (post-condition), à partir d’une situation donnée (pré-condition). La suite
d’opérations sera composée d’actions élémentaires, ou instructions.

1.1. Chaînes de caractères


Pour afficher un message à l’écran, ou imprimer un message sur papier, l’action d’écriture est utilisée.
1.1.1. Instruction « écrire »
Dans l’exemple suivant, nous voulons faire afficher un message de bienvenue.
Algorithme 1 :
écrire("Bonjour à tous") ;
L’instruction écrire est formée :
 du mot écrire,
 d’un paramètre, entre parenthèses, et qu’elle est toujours suivie d’un point virgule.
Ce paramètre est ici une chaîne de caractères entre guillemets, qui sera reproduite textuellement à l’écran
ou sur imprimante.
Un caractère peut être une lettre majuscule ou minuscule, un chiffre, un signe de ponctuation, ou un
espace pris entre apostrophe, par exemple : ‘A’, ‘b’. Une chaîne de caractère, ou chaîne pour abréger, est une
suite quelconque de caractères, entourée de guillemets, par exemple : "une classe". Si parmi ces caractères
nous voulons imprimer une valeur on écrit le % suivi d’un caractère qui indique le type de cette valeur
(algorithme 2).
1.1.2. Variables de type chaîne, l’instruction lire
Nous pouvons .souhaiter « personnaliser » notre message d’accueil en affichant le nom de l’utilisateur. Bien
entendu, l’ordinateur ne connaît ce nom à priori et devra donc commencer par le lui demander.
Algorithme 2 :
écrire("Comment vous appelez-vous ? ") ; lire(nom) ;
écrire("Bonjour %s ! \n",nom) ;
Le caractère s indique le type « chaîne de caractères ». Nous introduisons une variable de type « chaîne de
caractères » qui contiendra la valeur du nom. Notre ordinateur comporte un certain nombre de « cases », dites
aussi « emplacements en mémoire » , susceptibles de contenir une chaîne de caractères. Chacune de ces cases
seront identifiées par une « étiquettes » ou identificateur. L’identificateur ici est le mot nom.
Dans les parenthèses de l’instruction écrire, si parmi la chaîne de caractères il ya un caractère précédé d’un \,
ce caractère est un caractère spécial. Ici la séquence de caractères \n indique le retour à la ligne.
Chaque identificateur est une suite de caractères pris parmi les lettres, les chiffres et le caractère « souligné »,
mais doit commencer par une lettre. Ainsi : a, A3_b2, toto sont des identificateurs valables, alors que 35, 5A,
A+B ne le sont pas.

1
Exemple d’exécution de l’algorithme2 :
Comment vous appelez-vous ? Rakoto
Bonjour Rakoto !
Il faut bien faire la différence entre une constante chaîne (entre guillemets) et un identificateur de variable de
type chaîne (sans guillemets).
1.2. Fonctions et variables entières
L’algorithme présenté jusqu’ici devrait être recopié à chaque utilisation. Nous décidons maintenant d’en
faire une fonction c’est-à-dire une suite d’instructions nommée, que l’on pourra appeler par ce nom chaque
fois que l’on veut l’utiliser. Une fonction doit être déclarée afin de pouvoir ensuite l’appeler par son nom.
Syntaxe de la déclaration :
type_de_valeur_de _retour nom_fonction(arguments)
{ corps de le fonction
}
vide bonjour1(vide)
{ chaine nom ;
écrire("Comment vous appelez-vous ? ") ; lire(nom) ;
écrire("Bonjour %s ! \n",nom) ;
}
La déclaration comporte 3 parties :
 le type de la valeur de retour de la fonction ici vide c’est-à-dire que la fonction n’a pas de résultat.
 L’identificateur de la fonction ici bonjour1.
 L’argument de la fonction ici de type vide aussi. C’est-à-dire que la fonction ne reçoit aucune valeur de
l’extérieur.
1.2.1. Déclarations de variables
Elles servent à indiquer à l’ordinateur les identificateurs utilisés dans la fonction, ainsi que leur type. Dans
la fonction bonjour1, nous n’avons qu’une seule variable appelée nom et de type chaîne.
Syntaxe de déclaration : type identificateur ;
Exemple : chaine ch ;
ch est une variable de type chaine.
1.2.2. Variables entières et expressions arithmétiques
Nous voulons améliorer notre fonction, pour qu’il indique à l’utilisateur son âge. C’est l’ordinateur qui
calculera cet âge à partir de deux données : l’année actuelle et l’année de naissance de l’utilisateur.
vide bonjour2(vide)
{ chaine nom ;
entier annee, naissance ;
écrire("A quelle annee sommes-nous ? ") ; lire(annee) ;
écrire("Comment vous appelez-vous ? ") ; lire(nom) ;
écrire("Votre annee de naissance ? ") ; lire(naissance) ;
écrire("Bonjour %s ! \n",nom) ;
écrire("Vous etes age de %d ans \n", annee-naissance) ;
}
Nous avons introduit deux nouvelles variables annee et naissance.
Ces variables sont des nombres entiers, nous les déclarons donc de type entier.
Les entiers peuvent être positifs ou négatifs, et on peut leur appliquer les opérations arithmétiques classiques :
addition, soustraction, multiplication, division notés +, -, *, et /, ainsi que l’opérateur modulo, noté %, tel que n
% p donne le reste de la division entière de n par p ;
Exemples :
3+5 donnera 8
2 * (-6) donnera -12
12 / 3 donnera 4
12 % 3 donnera 0
14 % 3 donnera 2
On appellera une expression entière toute expression formée à partir de variables entières, de nombres
entiers, d’opérateurs, et éventuellement de parenthèses, selon les règles habituelles de l’algèbre.
Exemple :
Si les variables abc et xy ont respectivement pour valeurs 3 et -5, l’expression suivante :
(abc + 25) / (4 * (7 + xy)) aura pour valeur :
(3 + 25) / (4 * (7 + -5)), soit 28 / 8 c’est-à-dire 3.
Dans la fonction bonjour2, nous utilisons une expression entière dans la dernière instruction écrire. Il s’agit de
l’expression annee – naissance, dont la valeur est calculée par l’ordinateur.
Exemple d’exécution de bonjour2
En quelle annee sommes nous ? 1994
Comment vous appelez-vous ? Rakoto

2
Votre annee de naissance ? 1973
Bonjour Rakoto !
Vous etes age de 21 ans
1.2.3. Paramètres, instruction d’affectation
Avec la fonction bonjour2, nous devons demander à chaque utilisateur la valeur de l’année en cours. On peut
supposer que cette valeur est déjà connue de l’ordinateur (par son horloge interne ou bien par une saisie
préliminaire). On pourra alors paramétrer la fonction avec cette valeur.
vide bonjour3(entier annee)
{ chaine nom ;
entier naissance, age ;
écrire("Comment vous appelez-vous ? ") ; lire(nom) ;
écrire("Votre annee de naissance ? ") ; lire(naissance) ;
écrire("Bonjour %s ! \n",nom) ;
age = annee-naissance ;
écrire("Vous etes age de %d ans \n", age) ; }
Le paramètre annee est de type entier. Ce paramètre est appelé paramètre formel et il sera remplacé à l’appel
de la fonction par une valeur entière, ou bien par une variable de type entier, ou encore par une expression
entière. On dit qu’on fait le passage par valeur.
Exemples d’instructions d’appel
 bonjour3(1993) ;
 Si la variable ancour contient une valeur entière :
bonjour3(ancour) ;
On dira que 1993 ou ancour sont des paramètres effectifs, dont la valeur remplace celle du paramètre formel
lors de l’exécution.
D’autre part, nous introduisons dans la fonction une instruction d’affectation :
age = annee – naissance ;
Cette instruction permet de ranger une valeur dans une variable, autrement que par saisie directe (lire). Elle est
formée de l’identificateur de variable, puis du symbole d’affectation = puis d’une expression entière.
Cette expression entière pourra être un nombre entier, ou bien l’identificateur d’une autre variable entière,
ou encore une expression complexe dont la valeur est un nombre entier.
Exemple d’instructions d’affectation correctes
a1 = 3 ;
b=3*5;
c = a1 ;
c = (b + 6) / 4 ;
nb = nb + 1 ;
nb = nb * (a1 + b) ;
L’instruction d’affectation nb = nb + 1 est tout à fait différente d’une égalité mathématique. En effet,
l’égalité nb = = nb + 1 serait évidemment toujours fausse, quelle que soit la valeur de nb alors que l’instruction
nb = nb + 1 consiste simplement à modifier la valeur de la variable nb, en lui ajoutant 1.
Exemples d’instructions d’affectation incorrectes
a + 1 = 3 ; (a+ 1 n’est pas un identificateur de variable).
a = 3b ; (3b n’est ni un identificateur, ni une expression correcte)
Cette instruction d’affectation est aussi correcte :
x = y = z = 0 ; l’associativité est effectuée de droite à gauche. Cependant l’écriture suivante n’est pas acceptée :
double x = y = z = 0 ; // est rejeté.
Rappel : toute variable utilisée dans un programme doit être déclarée au début de l’algorithme, une fois et une
seule.
Après les déclarations, les valeurs des variables sont indéfinies. L’affectation de valeur à une variable peut
être effectuée autant de fois que l’on veut au cours de l’algorithme. La valeur de la variable sera alors modifiée
à chaque affectation.
Lorsqu’une variable apparaît en partie droite d’une instruction d’affectation, c’est que l’on suppose qu’elle
contient une valeur. Cette valeur devra lui avoir été affectée auparavant (initialisation), sinon l’on dira que la
valeur est indéfinie, et le résultat de l’affectation ne sera pas défini.
Exemple d’algorithme correct :
vide corr(vide)
{ entier a, b, c ;
a = 12 ; b= 5 ;
c=a–b;
a=a+c;
/* il s’agit ici de modifier la valeur de a, en lui ajoutant c */
b=a;}

3
Pour voir les contenus successifs des variables, nous allons en effectuer la
entier a, b, c ; trace : il s’agit tout simplement d’un tableau dans lequel pour chaque ligne de
a=5; l’algorithme, nous noterons les valeurs des variables.
c=a+b; a b c
d=c-2;
indéfini indéfini indéfini
int a, b, c ;
a = 12;b = 5 ; 12 5 indéfini
c=a-b;
a=a+c; 12 5 7
b = a; 19 5 7

19 19 7

Exemple d’algorithme incorrecte :


vide incorr(vide)
{ entier a, b, c ;
a=5;
c=a+b;
d=c-2;
a b C

indéfini indéfini Indéfini

5 indéfini Indéfini

5 indéfini ?

5 indéfini ?

1.3. Itérations et conditions


Nous voulons maintenant écrire une fonction qui saisit le nom et l’année de naissance de toute une série de
personnes, par exemple les étudiants de l’Ecole et affiche pour chaque étudiant son âge. Une première
méthode consiste à répéter les instructions de saisie et d’écriture un certain nombre de fois (on suppose que
l’Ecole a 5 étudiants).
vide etudiants1(entier annee)
{ chaine nom ; entier naissance, age ;
écrire("Nom d’un etudiant ? ") ; lire(nom) ;
écrire("Son annee de naissance ? ") ; lire(naissance) ;
age = annee – naissance ;
écrire("%s est age de %d ans\n",age) ;

écrire("Nom d’un etudiant ? ") ; lire(nom) ;


écrire("Son annee de naissance ? ") ; lire(naissance) ;
age = annee – naissance ;
écrire("%s est age de %d ans\n",age) ;

écrire("Nom d’un etudiant ? ") ; lire(nom) ;

4
écrire("Son annee de naissance ? ") ; lire(naissance) ;
age = annee – naissance ;
écrire("%s est age de %d ans\n",age) ;
écrire("Nom d’un etudiant ? ") ; lire(nom) ;
écrire("Son annee de naissance ? ") ; lire(naissance) ;
age = annee – naissance ;
écrire("%s est age de %d ans\n",age) ;

écrire("Nom d’un etudiant ? ") ; lire(nom) ;


écrire("Son annee de naissance ? ") ; lire(naissance) ;
age = annee – naissance ;
écrire("%s est age de %d ans\n",age) ;
}
C’est une méthode laborieuse, en raison de la répétition cinq fois la même séquence d’instructions. Un
autre inconvénient si l’école a moins de cinq étudiants, on lui demande des données inexistantes, s’il a plus de
cinq étudiants on ne lui demande rien au sujet des étudiants « supplémentaires ».
1.3.1. Instruction d’itération
Pour éviter cette répétition et demander les données le nombre de fois nécessaire et suffisant, on utilise
l’instruction d’itération.
vide etudiants2(entier annee)
{ chaine nom ;
entier naissance, age, nbetudiants, i ;
écrire("Combien d\’etudiants avez-vous ? ") ; lire(nbetudiants) ;
i=1;
tantque(i <= nbetudiants){
écrire("Nom d’un etudiant ? ") ; lire(nom) ;
écrire("Son annee de naissance ? ") ; lire(naissance) ;
age = annee – naissance ;
écrire("%s est age de %d ans\n",age) ;
i=i+1;
}
}
Dans la fonction nous demandons à l’utilisateur combien de fois il faudra répéter les instructions de saisie et
d’affichage, nous utilisons le constructeur tantque, afin d’itérer, ou répéter, ces instructions le bon nombre de fois.
Exemple d’exécution de la fonction etudiants2
( On suppose que le paramètre annee vaut 2008 ; en gras les réponses de l’utilisateur aux questions posées)
Combien d’etudiants ? 2
Nom d’un etudiant ? Rabe
Son annee de naissance ? 1990
Rabe est age de 18 ans
Nom d’un etudiant ? Rasoa
Son annee de naissance ? 1992
Rasoa est age de 16 ans

Les opérations de comparaison sont : <, <=, >, >=, ==, !=.
Les instructions sur lesquelles agit le constructeur tantque sont comprises entre { }. La forme générale d’une
instruction tantque est :
tantque (condition) { instruction1 ;
instruction2 ;……
}
Remarque : Cette instruction est elle-même une instruction, dite instruction d’itération. La suite d’instructions
est effectuée aussi longtemps que la condition demeure vraie.
1.3.2. Variables booléennes, instructions conditionnelles
Une autre méthode pour résoudre les problèmes posés par la fonction etudiants1 consiste à faire arrêter
l’itération par l’utilisateur, lorsqu’il le juge utile :
vide etudiants3(entier annee)
{ chaine nom ; entier naissance, age ;
booléen stop ;
stop = faux ;
tantque(non stop)faire
{ écrire("Nom d’un etudiant ? ") ; lire(nom) ;
si(nom <>’*’)
{ écrire("Son annee de naissance ? ") ; lire(naissance) ;

5
age = annee – naissance ; écrire("%s est age de %d ans\n",age) ;
}
sinon stop = vrai ;
}
}
La syntaxe d’une instruction conditionnelle est :
si(expression testée){ suite d’instructions 1}
sinon {suite d’instructions 2}
Si la condition est vraie, la suite d’instructions1 est effectuée ; si elle est fausse, on effectue la suite
d’instructions 2.
Les 2 suites d’instructions peuvent comporter à leur tour des instructions d’itérations ou encore d’autres
instructions conditionnelles.
Dans certains cas, on peut vouloir ne rien faire si la condition est fausse. On pourra alors se passer de la partie
sinon, et la forme se réduit à :
si(expression testée){ suite d’instructions 1}
Pour arrêter l’itération, nous avons introduit une variable de type booléen, ou une variable booléenne, stop. Ce
type signifie que la variable ne peut prendre que l’une de deux valeurs suivantes : vrai ou faux.
La première instruction que nous pouvons introduire sur cette variable est la négation :
Négation (non)
A Non A

vrai faux

faux vrai

Notons que A est faux est équivalent à non A, donc (A = faux)==(non A) et de même (A = vrai) ==(A) ;
dans la fonction etudiants3, c’est à l’utilisateur qu’incombe le soin d’arrêter l’algorithme en frappant une étoile
lorsqu’il le juge utile.
Nous pouvons imaginer que des utilisateurs s’amusent à faire tourner indéfiniment l’itération de la fonction
enfants3, en refusant de frapper un nom égal à ‘*’. Nous allons forcer la fonction à s’arrêter au bout de 20
itérations au maximum, en ajoutant un second test d’arrêt, contrôlé par un compteur.
vide etudiants4(entier annee)
{ chaine nom ; entier naissance, age, i ;
booléen stop ;
stop = faux ; /* en langage C, stop = 0 ; */
i=0;
tantque((non stop) et (i < 20))faire
{ écrire("Nom d’un etudiant ? ") ; lire(nom) ;
si(nom <>’*’)
{ écrire("Son annee de naissance ? ") ; lire(naissance) ;
age = annee – naissance ; écrire("%s est age de %d ans\n", age) ; i=i+1 ; }
sinon stop = vrai ;
}
}
La variable i a été utilisée à compter le nombre d’itérations.
Dans l’expression de test (non stop )et(i<20), nous utilisons une nouvelle opération, l’intersection. Le résultat
de l’intersection n’est vraie que si les deux opérandes on la valeur vrai.
A B A et B

vrai vrai vrai

vrai faux faux

faux vrai faux

faux faux faux

Intersection (et)

6
Dans certains cas nous serons amenés à utiliser l’opération d’union : Union (ou)
A B A ou B

vrai vrai vrai

vrai faux vrai

faux vrai vrai

faux faux faux

Assertions : nous pouvons améliorer la lisibilité de la fonction etudiants4 précédente en y ajoutant des
« assertions ». Une assertion est une expression logique (booléenne) ou condition qui est toujours vraie. Elle
est construite à partir de variables booléennes et de conditions élémentaires, à l’aide des opérateurs logiques non,
et et ou. Par convention, les assertions sont écrites, dans les algorithmes, en italiques, et entourés des signes /* et
*/. Afin de simplifier l’écriture, nous conviendrons aussi de remplacer, dans les assertions, le non par le
symbole ¬, le et par une virgule, et le ou par le symbole ν.
void etudiants4(entier annee)
/* spécification {}  {les âges des étudiants de l’utilisateur sont affichés}*/
{ chaine nom ; entier naissance, age, i ;
booléen stop ;
stop = faux ; /* en langage C, stop = 0 ; */
i=0;
tantque((non stop) et (i < 20))faire
{ écrire("Nom d’un etudiant ? ") ; lire(nom) ;
si(nom <>’*’)
{ écrire("Son annee de naissance ? ") ; lire(naissance) ;
age = annee – naissance ; écrire("%s  est age de %d ans\n", age) ; i=i+1 ; }
sinon /* nom=’*’ */ stop = vrai ;
} /* stop ν (i=20) */
}
Les assertions permettent de suivre la logique de l’algorithme et d’en vérifier le bien fondé. Mais qu’elles ne
modifient en rien le déroulement de l’algorithme. On dira que ce sont des commentaires.
Type caractère et instructions conditionnelles imbriquées.
Nous allons améliorer la fonction d’accueil bonjour en affichant Monsieur, Madame ou Mademoiselle devant le
nom de l’utilisateur. Pour cela, nous devons connaître son sexe, que nous coderons par la lettre ‘M’ ou ‘F’. Si le
sexe est féminin, nous devons de plus demander si la personne est mariée (réponse codée par ‘O’ pour oui, ‘N’
pour non). Nous introduisons deux nouvelles variables, formées chacune d’un seul caractère, que nous
déclarons de type car.
vide bonjour4(vide)
{ chaine nom ; car sexe, marie ;
écrire("Comment vous appelez-vous ? ") ; lire(nom) ;
écrire("Quel est votre sexe (M ou F) ? ") ; lire(sexe) ;
si(sexe == ‘M’) /*sexe = ‘M’*/
écrire("Bonjour, Monsieur %s\n", nom) ;
sinon /*sexe = ‘F’ */
{ écrire("etes-vous mariee (O ou N) ? ") ; lire(marie) ;
si(marie == ‘O’) /*sexe=‘F’, marie = ‘O’ */
{ écrire("Bonjour, Madame %s\n", nom) ;
sinon /* sexe = ‘F’, marie = ‘N’ */
écrire("Bonjour, Mademoiselle %s\n", nom) ;
}
}
}
La forme la plus générale de l’instruction conditionnelle est :
Si(expression testée 1) { suite d’instructions 1 }
sinon
{ si(expression testée 2){ suite d’instructions2}
Sinon si(expression testée 3){ suite d’instruction3 }…
Cette instruction est appelé instruction conditionnelle imbriquée.

7
1.4 Fonction avec résultat
Pour simplifier la fonction bonjour4, nous allons regrouper les instructions de « calcul » du titre Monsieur,
Madame, Mademoiselle, dans une fonction qui délivre (retourner) une valeur d’un type déterminé que nous
nommerons résultat.
chaine fonction(car sexe, marie)
{ si(sexe ==’M’)retour ‘Monsieur’ ;
Sinon si(marie ==’O’)retour ‘Madame’ ;
sinon retour ‘Mademoiselle’ ;
}
Le type de la valeur que retourne la fonction est déclarée dans la première ligne de la fonction suivie du nom
de la fonction et des arguments de cette fonction. Il s’agit ici du type chaîne. La valeur que retourne la fonction
(le résultat) est déterminée par une ou plusieurs instructions retour.
1.4.1. Passage par valeur
Une fonction passée par valeur ne peut retourner qu’un seul résultat à la fois. Si l’on veut qu’une fonction
modifie un ou plusieurs valeurs extérieures à la fonction on utilise le passage par pointeur.
Exemple : écrire une fonction qui donne la valeur vrai si la personne a plus de 18 ans sinon la fonction retourne
la valeur faux.
booléen majeur1(entier age)
{ si(age>=18)retour vrai ;
Sinon retour faux ;
}
Une solution simple et correcte :
booléen majeur2(entier age)
{ retour age>=18 ;
}
Exemple d’appel de la fonction :
majeur1(14) ;
ou entier n=23 ;
majeur2(n) ;
1.4.2. Passage par pointeur
Le but d’un algorithme est de modifier la valeur d’un paramètre : celui-ci est une donnée, par sa valeur à
l’entrée de l’algorithme, et un résultat, par sa valeur à la sortie de l’algorithme. Dans on utilise le passage par
pointeur.
vide permut( entier* a, entier* b)
{ entier c ;
c = *a ; *a = *b ; *b = c ;
}
8Exemple d’appel d’une telle fonction :
principale()
{ entier nb1, nb2 ;
écrire("saisir le premier nombre ? ") ; lire(nb1) ;
écrire("saisir le second nombre ? ") ; lire(nb2) ;
écrire("resultat avant echange\n") ;
écrire("nb1=%d\tnb2=%d\n",nb1, nb2) ;
permut(&nb1, &nb2) ;
écrire("resultat apres echange\n") ;
écrire("nb1=%d\tnb2=%d\n", nb1,nb2) ; }
Nous avons introduit deux nouveaux opérateurs : opérateur unaire d’adresse noté & et opérateur unaire
d’indirection noté *.
L’opérateur & permet d’obtenir l’adresse d’une variable. Elle s’applique à une variable. Si l’on a déclaré :
entier n ;
écrire("L\’adresse de n est : %s", &n) ;
/* &n permet d’obtenir l’adresse de n */
Pour que l’adresse de n existe, il faut tout d’abord déclarer n.
Par contre, l’opérateur d’indirection * permet d’obtenir le contenu de cette adresse. Elle doit s’appliquer à une
adresse.
*(&n) = 13 ; /*permet d’affecter la valeur 13 à la variable n, indirectement à partir de son adresse */
Cette écriture est équivalente à n=13 ;
Les développeurs du langage ont créé de nouveaux objets dont leurs contenus sont des adresses. Ces nou-
veaux objets sont appelés des pointeurs.
Déclaration d’un pointeur
entier * adri ; // adri est un pointeur qui pointe sur un entier.
Exemple :

8
Hypothèse r = ni, i <= p principale(vide)
{ entier n, *adrn ;
 i = p => r = np => résultat = r * adrn = &n ;
écrire("Adresse de n est %p\n", &n) ;
 i < p => r = r * n ; i = i + 1 ; => H *adrn = 25 ;
Itération tantque(i < p).... écrire("Le contenu de adr est %d ou %d\n", *adrn,
n) ;
Initialisation r = n ; i = 1 ; => H n = 123 ;
écrire("Le contenu de la variable n est
%d\n",*adrn) ; }
1.5. Raisonnement par récurrence
Une méthode proposée pour construire un algorithme itératif est basée sur la notion d’invariant et sur un
raisonnement par récurrence.
Exemple : soit à écrire une fonction qui retourne la valeur de n p, où p est un nombre entier positif, et n un
entier quelconque.
Nous pouvons définir récursivement np par les deux égalités suivantes :
n1 = n,
ni+1 = ni * n, i Є[1..p-1].
Supposons que nous avons partiellement résolu le problème : nous avons une variable r qui contient la valeur
de ni, et nous savons que i<=p.
On a donc l’hypothèse suivante : r = ni, i<=p.
Il y a deux possibilités :
 Soit i = p, alors r = np et le calcul est terminé.
 Soit i < p
Nous multiplions alors r par n en exécutant l’instruction : r = r * n ; r est donc alors égal à ni * n = ni+1.
Si nous incrémentons ensuite i de 1 en exécutant l’instruction : i = i + 1 ; nous obtenons de nouveau : r = ni,
i<=p.
L’instruction itérative s’écrit donc de la manière suivante :
/* r = ni, i<=p */
tantque(i<p)
{ r = r * n ; /* r = ni+1, i<p */
i = i + 1 ; /* r = ni, i <=p */
}
Pour laquelle l’assertion r = n i, i<=p est un invariant, à condition d’être vraie avant le début de l’itération. Pour
cela, il faut initialiser r et i avec des valeurs qui vérifient l’invariant.
Initialisation :
Il suffit d’écrire les affectations : r = n ; i = 1 ; /* r = ni, i <= p */
Pour vérifier l’hypothèse r = ni, i <= p quelle que soit la valeur de p > 0.
L’hypothèse ne devient un invariant que si l’initialisation a été effectuée.
A la sortie de l’instruction itérative nous pouvons affirmer :
 d’une part que ¬ (i < p) donc i >= p (condition de sortie de « tantque »)
 d’autre part que r = ni, i <= p (invariant).
De i <= p et i >= p, nous déduisons que i = p ;
de i = p et r = ni, nous déduisons que r = np.
En résumé, nous présenterons le raisonnement par récurrence sous la forme suivante :

L’algorithme complet est alors le suivant :


entier puissance (entier n, entier p)
/* spécification {p > 0} => {résultat = np}*/
{ entier r, i ;
r = n ; i = 1 ; /* r = ni, i<=p */
tantque(i < p){
r = r * n ; /* r = ni+1, i<p */

9
i = i + 1 ; /* r = ni, i <= p */ }
/* i <= p, r = ni, i <= p => r = np */
retour r ;
}
Le raisonnement par récurrence nous a permis :
 de construire l’itération,
 de dégager l’invariant,
 de trouver les initialisations nécessaires,
 et enfin de prouver que la valeur finale de r est bien celle que l’on cherche, en combinant la condition de
sortie de l’itération avec l’invariant.

10