Vous êtes sur la page 1sur 72

BTS Informatique de gestion 2e anne

Option administrateur de rseaux locaux dentreprise


Jean-Yves Fvrier

Algorithmique et langages
Autocorrection

Directrice de publication : Valrie Brard-Trigo


Les cours du Cned sont strictement rservs lusage priv de leurs destinataires et ne sont pas destins une utilisation collective. Les personnes
qui sen serviraient pour dautres usages, qui en feraient une reproduction intgrale ou partielle, une traduction sans le consentement du Cned,
sexposeraient des poursuites judiciaires et aux sanctions pnales prvues par le Code de la proprit intellectuelle. Les reproductions par
reprographie de livres et de priodiques protgs contenues dans cet ouvrage sont effectues par le Cned avec lautorisation du Centre
franais dexploitation du droit de copie (20, rue des Grands Augustins, 75006 Paris).

Sommaire
Squence 1 : Variables et instructrions

Squence 2 : Procdures et fonctions

15

Squence 3 : Tableaux, structures et types

19

Travaux dirigs 1

33

Travaux dirigs 2

46

Travaux dirigs 3

65

Squence 1

Variables et instructions
Exercice 1
La solution se trouve dans la suite du cours.

Exercice 2
Ce commentaire explique comment fonctionnent laccs un lment dun tableau,
laffectation et la boucle pour. Il na donc aucun intrt dans un programme car si vous
savez ce quest une affectation et une boucle pour, il ne vous apprend rien.
De plus, il est crit sans soin, car la variable LongueurTableau du code devient LongueurTab
dans le commentaire. Cest source de confusion.

Exercice 3
Ces termes sont normalement trs simples intuitivement, mais pour les dfinir ce nest
pas si facile ! Voici ce que je vous propose :
le type est un concept abstrait dfinissant quelque chose ; en programmation, le
type indique la nature dune valeur : entier, entier long, rel, caractre ;
la variable est un espace mmoire contenant une valeur. La variable sera toujours
dun type donn. Cest important car :
la taille de lespace mmoire utilis variera avec le type : il faut plus de place pour
stocker le nombre 1 701 254 988 520,489 que la lettre F ;
les valeurs tant stockes sous la forme de bits (des 0 et des 1), il faut connatre
leur nature pour les coder et les dcoder. Par exemple, la date 07/12/1970 ne sera
pas code sous la forme de 0 et de 1 de la mme faon que la chane "Mon teckel
dort." (Nous reverrons cela dans la suite du cours.)
La dclaration dune variable consiste lui rserver son espace mmoire. Il faut prciser
le type de la variable pour savoir quelle taille de mmoire lui accorder et dterminer la
technique de codage et dcodage en bits employer. Enfin, il faut toujours donner un
nom la variable dclare. Pourquoi ? Car si lon stocke une donne dans la mmoire,
cest pour sen servir. Et, pour sen servir, il faut pouvoir lidentifier par rapport aux autres
variables. Le plus simple est alors de lui donner un nom.
Pour le compilateur, nimporte quelle suite arbitraire de caractres constitue un nom
valide. Il est cependant vident que le dveloppeur doit utiliser un nom ayant un sens
par rapport au contenu de la variable pour que le code soit intelligible. Par exemple,
pour stocker le prix TTC dun produit, le nom PrixTTC sera videmment prfr Prix, P
ou, pire encore, PrixHT.

Exercice 4
Voir la suite du cours.

3
8 3987 TC PA 00

Squence 1

Exercice 5
Le principe sera le suivant :
1. Lutilisateur doit saisir le nombre tester.
2. Selon la valeur du calcul, on affiche pair ou impair.
Il faut videmment dclarer la variable (ce sera un entier). Cela donne :
Algo parit1
var
Nombre : entier
dbut
saisir "Entrez un nombre : ", Nombre
si Nombre mod 2 = 0
alors
Afficher "Le nombre est pair."
sinon
Afficher "Le nombre est impair."
fin si
fin
Si vous avez invers le test (Nombre mod 2 = 1 ou Nombre mod 2 <> 0), les deux instructions du alors et du sinon sont permutes :
Algo parit2
var
Nombre : entier
dbut
saisir "Entrez un nombre : ", Nombre
si Nombre mod 2 <> 0
alors
Afficher "Le nombre est impair."
sinon
Afficher "Le nombre est pair."
fin si
fin
Assurez-vous que vous tes daccord avec cette proposition : ces deux algorithmes donnent exactement le mme rsultat .

Exercice 6
Voir la suite du cours.

4
8 3987 TC PA 00

Variables et instructions

Exercice 7
1er bloc
01
02
03
04
05
06

afficher "avant boucle"


tant que (2 = 3) faire
afficher "dans boucle"
x := x/0
fin tant que
afficher "aprs boucle"

Ce bloc possde trois instructions :


1. Afficher en ligne 1.
2. La boucle tant que en lignes 2 5. Cette instruction en contient deux : afficher
(ligne 3) puis une affectation (ligne 4).
3. Afficher en ligne 6.
Comme nous lavons dj vu (paragraphe 2), on va excuter la premire instruction, puis
la deuxime et enfin la troisime :
1re instruction : lapplication affiche avant boucle ;
2e instruction : on excute le tant que (valuation du boolen, sil est vrai on excute
les instructions). Eh bien, le boolen vaut faux (en effet 2 nest pas gal 3). On
nexcute donc pas les instructions contenues dans le tant que et on passe linstruction suivante (sous entendu suivant le tant que , donc ligne 6) ;
3e instruction : lapplication affiche aprs boucle.
Lexcution de ce bloc produira donc laffichage suivant :
avant boucle
aprs boucle
Notez bien que 2 = 3 est tout fait juste syntaxiquement (comme x = y). Cest une constante boolenne qui vaut faux. De mme, 1+0 est une constante entire valant 1.
La leon retenir ? Si le boolen est toujours faux, les instructions contenues dans la
boucle ne sont pas excutes ; cette dernire ne sert donc rien.
Le bloc prcdent pouvait donc scrire :
afficher "avant boucle"
afficher "aprs boucle"
Le pige rsidait dans le boolen mais aussi dans la ligne 4 : la division par zro provoque
une erreur si linstruction est excute. Mais ce nest pas le cas ici, donc pas derreur.
2e bloc
afficher "avant boucle"
i := 1
tant que (i > 0) faire
afficher "dans boucle"
i := i+1
fin tant que
afficher "aprs boucle"
5
8 3987 TC PA 00

Squence 1

Ici, quatre instructions (dans lordre afficher, une affectation, la boucle contenant un
afficher et une affectation puis encore un afficher). Les deux premires sexcutent
sans problme. Quand on arrive sur la boucle, i vaut 1.
Excution de la boucle :
1. On value le boolen : i > 0 correspond 1 > 0, ce qui est vrai. Les instructions de
la boucle sont excutes (on affiche dans boucle puis on incrmente i qui vaut alors
2) puis on recommence lexcution de la boucle.
2. On value le boolen : i > 0 correspond 2 > 0, ce qui est vrai. Les instructions de
la boucle sont excutes (on affiche dans boucle puis on incrmente i qui vaut alors
3) puis on recommence lexcution de la boucle.
3. On value le boolen : i > 0 correspond 3 > 0, ce qui est vrai. Les instructions de
la boucle sont excutes (on affiche dans boucle puis on incrmente i qui vaut alors
4) puis on recommence lexcution de la boucle.
4. Inutile de continuer : comme on ajoute 1 i, il va crotre indfiniment (valant 5,
6) et sera videmment toujours suprieur 0. Le boolen ne sera jamais faux
donc la boucle ne sarrtera jamais. La dernire instruction du bloc ne sera jamais
excute.
Voici laffichage que nous aurons :
avant boucle
dans boucle
dans boucle
dans boucle
dans boucle

La leon retenir ? Si le boolen est toujours vrai, la boucle est excute indfiniment.
Pour viter cela, il faut vrifier que les instructions incluses dans la boucle rendent le
boolen faux un moment donn.
Simplifions le bloc prcdent. Il pouvait scrire :
afficher "avant boucle"
tant que vrai faire
afficher "dans boucle"
fin tant que
Je nessaye plus dafficher aprs boucle puisque je sais maintenant que je ny arriverai
jamais. Je nutilise plus i puisque en fait il ne sert rien.
3e bloc
afficher "avant boucle"
i := 1
tant que (i > 0) faire
afficher "dans boucle"
i := i-1
fin tant que
afficher "aprs boucle"
Cest le mme bloc que prcdemment sauf que lon dcrmente i dans la boucle.

6
8 3987 TC PA 00

Variables et instructions

On afche avant boucle. Quand on arrive sur la boucle, i vaut 1.


Excution de la boucle :
1. On value le boolen : i > 0 correspond 1 > 0, ce qui est vrai. Les instructions de la
boucle sont excutes (on affiche dans boucle puis on dcrmente i qui vaut alors
0) puis on recommence lexcution de la boucle.
2. On value le boolen : i > 0 correspond 0 > 0, ce qui est faux. Lexcution de la
boucle sarrte.
On arrive la dernire instruction du bloc qui affiche aprs boucle.
Voici laffichage que nous aurons :
avant boucle
dans boucle
aprs boucle
On voit bien que les instructions dans la boucle vont rendre le boolen faux un jour ou
lautre : partant dun nombre positif, on le dcrmente ; on arrivera donc forcment 0.
Le bloc pouvait scrire :
afficher "avant boucle"
afficher "dans boucle"
afficher "aprs boucle"
4e bloc
afficher "avant boucle"
i := 5
j := -1
tant que (i > 0) faire
afficher "dans boucle"
j := j+1
fin tant que
afficher "aprs boucle"
Nous avons 5 instructions, dans lordre afficher, deux affectations, une boucle puis afficher. Lorsque lon arrive sur la boucle, i vaut 5 et j vaut 1.
Maintenant que nous avons un peu de pratique, essayons de raisonner sans excuter
la main le programme.
Dans la boucle, on ralise un affichage et on modifie la valeur de j. Celle de i reste
inchange. Ainsi, le boolen i > 0 ne change pas. Ce sera toujours 5 > 0 (puisque i vaut
5). Or cela est vrai. La boucle ne sarrte donc pas.

Attention au pige bte (classique, mais bte) : x >= x est vrai mais x > x est faux : un nombre
nest pas plus grand que lui-mme.
7
8 3987 TC PA 00

Squence 1

Voici laffichage que nous aurons :


avant boucle
dans boucle
dans boucle
dans boucle

La leon retenir ? Pour que la boucle sarrte un jour, il faut, nous lavons vu, que les
instructions contenues dans la boucle rendent le boolen faux. Et, pour que cela arrive,
il faut que les variables utilises dans le boolen soient modifies par les instructions.
Ici, comme le boolen est fonction de i et que i nest pas modifi dans la boucle, on sait
que la boucle ne sexcutera jamais (boolen initialement faux) ou ne sarrtera pas
(boolen initialement vrai).
Une dernire remarque : on modifie la variable j mais on ne sen sert jamais. On peut
donc lenlever car elle ne sert rien.
Le bloc prcdent pouvait donc scrire :
afficher "avant boucle"
i := 5
tant que (i > 0) faire
afficher "dans boucle"
fin tant que
Voire :
afficher "avant boucle"
tant que (5 > 0) faire
afficher "dans boucle"
fin tant que
Soit :
afficher "avant boucle"
tant que vrai faire
afficher "dans boucle"
fin tant que

Exercice 8
1er bloc
rpter
saisir "Entrez lge : ", ge
jusqu (ge > 0) et (ge < 120)

8
8 3987 TC PA 00

Variables et instructions

Reprenons les tapes du cours :


1. On excute les instructions de la boucle : on affiche Entrez lge : et on attend la
saisie de lutilisateur que lon stocke dans la variable ge.
2. On value le boolen. Celui-ci vaudra vrai si lge est compris entre 0 et 120 exclus
et faux sinon. Ainsi, si ge vaut moins de 1 ou plus que 119 (cest une variable
entire), on recommence la boucle.
Que fait cette boucle ? Elle assure que la valeur saisie est correcte puisque tant que lutilisateur rentre une valeur fantaisiste, on lui redemande.
2e bloc
rpter
x := x/0
jusqu x = x
On excute les instructions dans la boucle Le programme plante car on fait une division
par zro.
Tout cela pour vous rappeler que lon excute les instructions de la boucle avant de calculer la valeur du boolen (ici, x = x) et non aprs comme avec un tant que. Revoyez la
division par zro du premier bloc de lexercice 7.

Exercice 9
1er bloc
pour i de 1 10 pas 5
afficher i
fin pour
On reprend la dmarche du cours (avec le cas entier1 < entier2) :
1. i est initialis 1.
2. i tant infrieur ou gal 10 (1 < 10), on excute les instructions contenues dans la
boucle. On affiche donc i, soit 1.
3. On incrmente i de 5. Lindice i vaut alors 6.
4. i tant infrieur ou gal 10 (6 < 10), on excute les instructions contenues dans la
boucle. On affiche donc i, soit 6.
5. On incrmente i de 5. Lindice i vaut alors 11.
6. i est suprieur 10 (11 > 10). On sarrte.
Ce nest pas un algorithme trs utile ! Son objet est simplement de vous rappeler le
fonctionnement du pour.
2e bloc
pour i de 10 1 pas 1
pour j de 10 1 pas -1
afficher i, "x", j, "=", i*j
fin pour
fin pour

9
8 3987 TC PA 00

Squence 1

On reprend la dmarche du cours (avec le cas entier1 > entier2) :


1. i est initialis 10.
2. i tant suprieur ou gal 1 (10 > 1), on excute linstruction contenue dans la
boucle soit une autre boucle (avec le cas entier1 > entier2) :
a. j est initialis 10.
b. Comme j est suprieur ou gal 1 (10 > 1), on excute la boucle (donc on affiche
10x10 = 100) puis on ajoute 1 j (qui vaut donc 9).
c. Comme j est suprieur ou gal 1 (9 > 1), on excute la boucle (donc on affiche
10x9 = 90) puis on ajoute 1 j (qui vaut donc 8).
d. etc. On acclre jusqu ce que j vaille 1.
e. Comme j est suprieur ou gal 1 (1=1), on excute la boucle (donc on affiche
10x1 = 10) puis on ajoute 1 j (qui vaut donc 0).
f. Comme j est infrieur 1, lexcution de la boucle j sarrte. On revient la
boucle i.
3. On ajoute 1 i (qui vaut alors 9).
4. i tant suprieur ou gal 1 (9 > 1), on excute linstruction contenue dans la boucle soit une autre (avec le cas entier1 > entier2) :
a. j est initialis 10.
b. Comme j est suprieur ou gal 1 (10 > 1), on excute la boucle (donc on affiche
9x10 = 90) puis on ajoute 1 j (qui vaut donc 9).
c. Comme j est suprieur ou gal 1 (9 > 1), on excute la boucle (donc on affiche
9x9 = 81) puis on ajoute 1 j (qui vaut donc 8).
d. etc. On acclre jusqu ce que j vaille 1.
e. Comme j est suprieur ou gal 1 (1=1), on excute la boucle (donc on affiche
9x1 = 9) puis on ajoute 1 j (qui vaut donc 0).
f. Comme j est infrieur 1, lexcution de la boucle j sarrte. On revient la
boucle i.
5. On ajoute 1 i (qui vaut alors 8).
6. etc. On acclre jusqu ce que i vaille 1. Comme i est gal 1, on excute linstruction contenue dans la boucle soit une autre boucle (on affichera 1x10 = 10, 1x9 =
9 jusqu 1x1 = 1). On ajoute 1 i qui vaut alors 0.
7. i tant infrieur 1, lexcution de la boucle est termine.
Les deux boucles sont dites imbriques (lune est lintrieur de lautre). Chaque itration
de la boucle externe (ici i) entrane lexcution complte de la boucle interne (ici j).

Exercice 10
Appliquons le cours :
1. i est initialis 1 ; i tant infrieur 5, on excute le corps de la boucle (on affiche
i soit 1 puis on retranche 1 i qui vaut alors 0).
2. On ajoute 1 i qui vaut alors 1 puis on recommence la boucle : comme i est infrieur 5, on excute le corps de la boucle (on affiche 1 et on retranche 1 i qui
vaut alors 0).
3. On ajoute 1 i qui vaut alors 1 puis on recommence la boucle : comme i est infrieur 5, on excute le corps de la boucle (on affiche 1 et on retranche 1 i qui
vaut alors 0).
4.

10
8 3987 TC PA 00

Variables et instructions

Que se passe-t-il ? La boucle ne sarrte jamais car chaque itration le corps de boucle
dcrmente i alors que la boucle elle-mme lincrmente. Cette instruction est assez illisible. Une rgle non crite veut que lon ne modifie pas la main lindice de la boucle
pour. Cet indice doit tre utilis uniquement en lecture, sinon on ne sy retrouve pas.
Certains langages interdisent dailleurs de modifier lindice. Pour nous, cela constituera
une rgle de validation.

Exercice 11
Il suffit dappliquer le cours sur le pour : dabord on initialise lindice de boucle 1 puis,
tant que lindice est infrieur ou gal 10, on excute linstruction afficher et on incrmente lindice.
Boucle tant que
i := 1
tant que i <= 10 faire
afficher i
i := i+1
fin tant que
Boucle rpter
i := 1
rpter
afficher i
i := i+1
jusqu i > 10
Vous remarquez que ces suites dinstructions sont moins lisibles que le pour : il y a plus
de lignes, la condition darrt est moins vidente et surtout il faut grer soi-mme lindice !
Notez bien la symtrie des boucles tant que et rpter : les deux boolens sont la ngation lun de lautre puisque dans un cas la boucle est termine lorsque le test est vrai, et
dans lautre cas, elle est termine quand il est faux.

Exercice 12
Vous ne vous attendez pas un corrig, nest-ce pas ? Et bien, vous avez raison.

Exercice 13
Dans lexercice 12, vous tes en fin de paragraphe. Vous lavez donc lu une fois et,
lissue de cette lecture, vous devez dcider de le relire ou non.

11
8 3987 TC PA 00

Squence 1

Si lalgorithme est prsent en dbut de paragraphe, vous lexcuterez avant tude de ce


dernier. Il doit donc vous dire de lire le paragraphe puis de vrifier votre assimilation.
Cela donnera une boucle rpter :
rpter
faites une pause
lisez le paragraphe 5
jusqu ce que vous layez compris, ce satan paragraphe
Cette correction nest pas parfaite car la boucle rpter nest pas adapte. Le problme
vient de la pause :
dans lexercice 12, la pause est l pour vous viter de boucler immdiatement sur
une seconde lecture. En effet, si vous navez pas compris le cours, il faut laisser passer un peu de temps pour que les choses dcantent avant de recommencer ;
pour obtenir le mme rsultat, je suis oblig de vous faire commencer par une
pause. Pour sauver la face, nous dirons qu la premire itration, cette pause
spare les paragraphes 4 et 5.

Exercice 14
Cest simple, je dois employer une boucle pour.
Pour i de 1 5 faire
lire le paragraphe 5
faire une pause
fin pour

Exercice 15
Le fait de devoir lire 5 fois fait penser un pour. Un peu de rflexion cartera cette instruction car on arrte la lecture ds que lon a compris.
On lira donc le paragraphe 5 :
tant que lon na pas compris et que lon na pas atteint les 5 lectures ;
jusqu ce que lon ait compris ou que lon ait atteint les 5 lectures.
Vrifiez que ces deux formulations sont quivalentes.
Comme lalgorithme doit tre crit en fin de paragraphe 5, une lecture a dj t faite.
Il faut donc tester immdiatement la comprhension puis passer la suite ou relire (on
dispose de 4 relectures puisque lon a droit 5 lectures).

Vous noterez la transversalit de ce cours : je vous donne un bel exemple de concordance des
temps.
12
8 3987 TC PA 00

Variables et instructions

Cela donnera le code suivant :


NumLecture := 1 // numro courant de la lecture : on en a fait 1
tant que (le cours nest pas compris) et (NumLecture < 5) faire
faire une pause
relire le paragraphe 5
NumLecture := Numlecture +1
fin tant que
Voyez bien que lon quitte la boucle lorsque son test est faux, savoir ds que lune des
deux conditions suivantes est fausse :
le cours nest pas compris ;
le nombre de lectures faites est infrieur 5.
Dit autrement, on quitte la boucle lorsque son test est faux, savoir ds que lune des
deux conditions suivantes est vraie :
le cours est compris ;
le nombre de lectures faites est gal 5.

Exercice 16
Nous avons vu dans lexercice 11 quune boucle pour pouvait scrire sous forme dun
tant que ou dun rpter. La difficult est donc de choisir la bonne instruction !
Analysons le problme : pour chaque heure de 0 23 on veut afficher les minutes de 0
59. Et bien, cela nous fera deux boucles pour imbriques :
Algorithme trois_mille_six_cent_fois_par_heure_la_seconde_chuchote_souviens_toi
var
h,m : entier
dbut
pour h de 0 23
pour m de 0 59
afficher h, ":", m
fin pour
fin pour
fin
Je nai pas vu la difficult annonce, M. Fvrier. Suis-je pass ct ? Bah, si vous ne
lavez pas vue, cest quen effet vous lavez loupe. Que se passe-t-il lorsque lon pense
afficher 08 :05 ? Eh bien, on affiche 8:5. En effet, lentier 8 saffiche 8 et non 08 (sinon,
pourquoi ne pas lafficher 00000000000000000000000000000000000000000000008 ou
pire encore ?).
Nous allons rajouter des alternatives pour prendre en compte les valeurs infrieures 10
et les prcder dun zro.

13
8 3987 TC PA 00

Squence 1

Algorithme trois_mille_six_cent_fois_par_heure_la_seconde_chuchote_souviens_toi
var
h,m : entier
dbut
pour h de 0 23
pour m de 0 59
si h < 10
alors
afficher "0"
fin si
afficher h, ":"
si m < 10
alors
afficher "0"
fin si
afficher m
fin pour
fin pour
fin
Le code est dj nettement moins lisible, mais laffichage sera impeccable ! Notez que je
ne me soucie pas du retour la ligne.

14
8 3987 TC PA 00

Squence 2

Procdures et fonctions
Exercice 17
Cest un passage par valeur (il ny a pas de var). Pour laffichage du programme et la suite
de lexercice, retournez dans le cours.

Exercice 18
Nous crivons une fonction renvoyant le nombre le plus grand. La modification ventuelle des paramtres ne doit pas avoir dincidence dans les variables du programme
principal. On ralise donc un passage par valeur.
Algorithme maximum
var
e1, e2 : entier
fonction Maximum (a : entier, b : entier) : entier
dbut
si a > b
alors
Retourner (a)
sinon
Retourner (b)
fin si
fin
dbut
saisir "Entrez le premier nombre", e1
saisir "Entrez le second nombre", e2
afficher "Nombre le plus grand : ", Maximum (e1, e2)
fin
On pouvait passer par une variable intermdiaire dans la fonction :
fonction Maximum (a : entier, b : entier) : entier
var
c : entier
dbut
si a > b
alors

15
8 3987 TC PA 00

Squence 2

c := a
sinon
c := b
fin si
Retourner (c)
fin
(Le reste du code est inchang.)

Exercice 19
Je vais faire deux fonctions : une pour la remise et une pour le port.
De quelles donnes ai-je besoin ? Vu le sujet, uniquement du nombre darticles et du
total de la commande. Il est notamment inutile de saisir le nom des produits commands
ou leur prix.
Voici lalgorithme :
Algorithme commande
var
NbrArticles : entier
TotalCommande : rel
Port : rel
Remise : rel
fonction CalculRemise (NombreArticles : entier, TotCom : rel) : rel
dbut
selon NombreArticles
cas 1, 2 : Retourner (0)
cas 3, 4 : Retourner (TotCom*0.05)
cas 5, 6, 7 : Retourner (TotCom*0.1)
cas sinon : Retourner (TotCom*0.15)
fin selon
fin
fonction CalculPort (TotalAvecRemise : rel) : rel
dbut
si TotalAvecRemise < 77
alors
Retourner (7,7)
sinon
si TotalAvecRemise <= 150
alors
Retourner (4)
sinon
Retourner (0)

16
8 3987 TC PA 00

Procdures et fonctions

fin si
fin si
fin
dbut
saisir "Nombre darticles achets :", NbrArticles
saisir "Total commande :", TotalCommande
Remise := CalculRemise (NbrArticles, TotalCommande)
afficher "Remise : ", Remise
Port := CalculPort (TotalCommande-Remise)
afficher "Port : ", Port
afficher "Net payer : ", TotalCommande-Remise+Port
fin
Les diffrents montants doivent tre des nombres rels. Notez que CalculPort ne peut
tre ralis quavec un si et pas un selon cas car TotalAvecRemise est un rel.
Pour chaque sous-programme, il faut sassurer de nutiliser que les paramtres ncessaires. De plus, les fonctions commenant tre complexes, il est indispensable de vrifier
pour chacune que, quelle que soit son excution dpendant des alternatives incluses, on
excute une instruction Retourner.

Exercice 20
Remarque liminaire : si les valeurs sont gales, je peux renvoyer indiffremment lune ou
lautre. Je nai donc pas me soucier de ce cas.
La fonction :
fonction Minimum (a : entier, b : entier) : entier
dbut
si a < b
alors
Retourner (a)
sinon
Retourner (b)
fin si
fin
Exemple dutilisation de la fonction :
z := Minimum (i, 5)

17
8 3987 TC PA 00

Squence 2

Sous forme de procdure, cela donne :


procdure Minimum (a : entier, b : entier, var Rsultat : entier)
dbut
si a < b
alors
Rsultat := a
sinon
Rsultat := b
fin si
fin
Notez bien que le nom du nouveau paramtre est totalement arbitraire. Jai mis Rsultat
car cest un nom cohrent (je renvoie bien un rsultat) mais tout autre nom restait acceptable. Jai dailleurs hsit avec Min. Minimum nest pas utilisable car il est dj pris : cest
le nom de la procdure.
Exemple dutilisation de la procdure :
Minimum (i, 5, z)

Exercice 21
Le corrig est dans la suite du cours.

18
8 3987 TC PA 00

Squence 3

Tableaux, structures et types


Exercice 22
1) 60 tudiants et moyenne annuelle.
Je vais stocker 60 valeurs relles, soit :
var
NotesBTS : tableau[60] de rels
2) 2 classes de BTS de 30 tudiants chacune.
Je choisis didentifier la classe (premier indice) puis ltudiant dans la classe (second
indice). Jai toujours 60 valeurs, mais sous la forme deux fois trente :
var
NotesBTS : tableau[2, 30] de rels
Je choisis dindicer dabord la classe puis ltudiant car cela me semble plus logique vu le
rel modlis. Linverse (soit tableau[30,2]) est possible comme nous lavons vu dans le
cours. Limportant est de choisir une version et de sy tenir.
3) 2 classes de BTS de 30 tudiants chacune, 20 notes.
Je choisis didentifier la classe (premier indice, vaudra 1 ou 2) puis ltudiant dans la
classe (deuxime indice, de 1 30) et enfin la note (troisime indice, allant de 1 20).
Jai 2 classes x 30 tudiants x 20 notes soit 1 200 valeurs :
var
NotesBTS : tableau[2, 30, 20] de rels
Par exemple, la dernire note (soit la 20e) de ltudiant numro 12 qui est en 2e anne sera :
NotesBTS[2e anne, tudiant 12, dernire note] soit NotesBTS[2, 12, 20].

Exercice 23
1) 2 classes de BTS de 30 tudiants chacune, 2 semestres, 10 notes par semestre.
Je choisis didentifier la classe (premier indice) puis ltudiant dans la classe (deuxime
indice) puis le semestre (troisime indice) et enfin la note (quatrime indice). Jai 2 classes
x 30 tudiants x 2 semestres x 10 notes soit 1 200 valeurs :
var
NotesBTS : tableau[2, 30, 2, 10] de rels

19
8 3987 TC PA 00

Squence 3

2) 2 classes de BTS de 30 tudiants chacune, 2 semestres, 11 matires et 10 notes par


semestre.
Pour la premire fois, jai vraiment le choix de lordre des indices en fonction de mes
perceptions. Les quatre ordres suivant ont un sens :
classe, tudiant, semestre, matire et enfin note ;
classe, tudiant, matire, semestre, et enfin note ;
classe, semestre, tudiant, matire et enfin note ;
classe, semestre, matire, tudiant, et enfin note ;
Encore une fois, tout dpend ce que je veux mettre en avant. Si je gre des tudiants
qui ont des notes, ce sera lun des deux premiers choix. Sil me semble plus lisible de
choisir la priode scolaire (anne puis semestre) avant ltudiant, ce sera lune des deux
dernires solutions.
Encore une fois, nimporte laquelle des quatre versions est correcte et me permettra de
faire tous les traitements que je dsire.
Je vais choisir la troisime proposition, soit classe (indice maximum 2), semestre (indice
maximum 2), tudiant (indice maximum 30), matire (indice maximum 11) et enfin note
(indice maximum 10) :
var
NotesBTS : tableau[2, 2, 30, 11, 10] de rels
3) 2 BTS
Il me suffit de rajouter un indice (je le mettrai en premier) valant 1 pour BTS IG et 2 pour
BTS NRC :
var
NotesBTS : tableau[2, 2, 2, 30, 11, 10] de rels
Il est bien vident que, pour pouvoir utiliser un tableau, vous devez connatre le rle de
chaque indice. Les trois premiers indices du tableau ci-dessus vont de 1 2. Il est impossible de deviner lequel reprsente la classe, le semestre ou le BTS.

Exercice 24
La troisime note dconomie (8e matire) du premier semestre pour ltudiant 17 en
seconde anne de BTS IG (1er BTS) ?
En remettant mes critres dans lordre des indices, cela donne :
NotesBTS[bts ig, seconde anne, premier semestre, tudiant 17, matire 8, note 3]
La rponse est donc NotesBTS[1, 2, 1, 17, 8, 3].
Les notes dconomie au troisime contrle du premier semestre pour tous les tudiants
de seconde anne de BTS IG ?
Je prends en compte tous les tudiants et non plus le 17e uniquement. Je vais donc
devoir faire varier le 4e indice sur toute sa plage de valeurs, soit de 1 30. Les notes
voulues seront donc accessibles par NotesBTS[1, 2, 1, 1, 8, 3], NotesBTS[1, 2, 1, 2, 8, 3], ,
NotesBTS[1, 2, 1, 30, 8, 3].

20
8 3987 TC PA 00

Tableaux, structures et types

Pour faire varier cet indice, jutiliserai une boucle pour allant de 1 30. Pour simplifier
lcriture, je vais remplacer lindice en question par une toile ( * ). Cela reprsentera
que toutes les valeurs possibles (donc de 1 30) doivent tre considres.
Cela donne donc en condens : NotesBTS[1, 2, 1, *, 8, 3].
Les notes dconomie au premier semestre pour tous les tudiants de seconde anne
de BTS IG ?
Non seulement je prends en compte tous les tudiants, mais je considre en plus toutes
les notes et non uniquement la troisime. Comme jai 10 notes et 30 tudiants, cela
englobe 300 lments de NotesBTS. Vous les trouverez en faisant varier lindice des
tudiants (le quatrime) dans toute sa plage de 1 30 et, pour chacune des valeurs, en
faisant varier lindice des notes (le dernier) sur toute sa plage de 1 10.
Par programmation, nous ferions deux boucles imbriques. Avec notre notation toile,
cela donne en condens : NotesBTS[1, 2, 1, *, 8, *].
Les notes dconomie au premier semestre pour tous les tudiants de BTS IG ?
Non seulement je prends en compte tous les tudiants et toutes les notes, mais je considre en plus les deux annes de BTS IG et non uniquement la seconde. Comme jai 10
notes, 30 tudiants et deux annes, cela englobe 600 lments de NotesBTS. Vous les
trouverez en faisant varier lindice des annes de BTS IG (le deuxime) dans toute sa
plage de 1 2 et, pour chacune des valeurs, en faisant varier lindice des tudiants (le
quatrime) dans toute sa plage de 1 30 et, pour chacune des valeurs, en faisant varier
lindice des notes (le dernier) sur toute sa plage de 1 10.
Par programmation, nous ferions trois boucles imbriques. Avec notre notation toile,
cela donne en condens : NotesBTS[1, *, 1, *, 8, *].
Les notes dconomie au premier semestre pour tous les tudiants, tous BTS confondus ?
Je ne dtaille plus. Il faut, en plus du cas prcdent, faire varier le premier indice reprsentant le BTS, soit : NotesBTS[*, *, 1, *, 8, *]. On utiliserait quatre boucles imbriques.
Les notes dconomie, toute classe, semestre et tudiant confondus ?
Je ne dtaille plus. Il faut, en plus du cas prcdent, faire varier le troisime indice reprsentant le semestre, soit : NotesBTS[*, *, *, *, 8, *].

Exercice 25
Il me faut cinq boucles imbriques. Le sous-programme qui gnralise du sujet signifie que je vais passer en paramtre le tableau et le numro de la matire dont je veux la
moyenne. Cela me permet de calculer la moyenne de nimporte quelle matire.

21
8 3987 TC PA 00

Squence 3

Voici le code :
fonction MoyenneMatire (Note : tableau[2,2,2,30,11,10] de rels, NumMatire : entier) : rel
var
Bts, Anne, Semestre, tudiant, Note : entier
Cumul : rel
dbut
Cumul := 0
Ok pour le paramtre ?
pour Bts de 1 2 faire
Il dtermine la matire.
pour Anne de 1 2 faire
pour Semestre de 1 2 faire
pour tudiant de 1 30 faire
pour Note de 1 10 faire
Cumul := Cumul + Note[Bts, Anne, Semestre, tudiant, NumMatire, Note]
fin pour
fin pour
fin pour
fin pour
fin pour
Retourner (Cumul/2400)
fin
La moyenne des notes dune matire, cest bien la somme des notes de cette matire
divise par le nombre total de notes de la matire, soit 2*2*2*30*10 soit 2 400.
Il est possible de compter le nombre de notes dans les boucles :
fonction MoyenneMatire (Note : tableau[2,2,2,30,11,10] de rels, NumMatire : entier) : rel
var
Bts, Anne, Semestre, tudiant, Note : entier
Cumul : rel
NbrNotes : entier
dbut
Cumul := 0
NbrNotes := 0
pour Bts de 1 2 faire
pour Anne de 1 2 faire
pour Semestre de 1 2 faire
pour tudiant de 1 30 faire
pour Note de 1 10 faire
Cumul := Cumul + Note[Bts, Anne, Semestre, tudiant, NumMatire, Note]

22
8 3987 TC PA 00

Tableaux, structures et types

NbrNotes := NbrNotes + 1
fin pour
fin pour
fin pour
fin pour
fin pour
Retourner (Cumul/NbrNotes)
fin
Cest moins efficace car on doit effectuer 2 400 additions supplmentaires. Mais cela
vite les erreurs de calcul.
Pour viter les erreurs et rester efficace, linstruction Retourner de la premire fonction
pouvait scrire :
Retourner (Cumul/(2*2*2*30*10))
On comprend alors parfaitement ce que reprsente le chiffre divisant Cumul.
Synchronisons-nous. Pour afficher la moyenne des notes dconomie, il faut appeler la
fonction. Si notre tableau sappelle NotesBTS, on crira :
Afficher MoyenneMatire(NotesBTS, 8)

Exercice 26
Si vous considrez que 3,4 est un nombre rel, alors vous voulez accder un lment
dont lindice nexiste pas. En effet, lindice est un entier. Dailleurs, comme dans ce cours
lindice est la position de llment, il est vident que la position 3,4 na pas de sens.
Si vous considrez quun indice ne pouvant tre quentier, 3,4 constitue laccs un
lment dans un tableau deux dimensions (genre ligne 3, colonne 4 ), cela ne fonctionne toujours pas puisque notre tableau ne possde quune dimension.

Exercice 27
Cest le mme principe que pour lexercice prcdent : notre criture na aucun sens
puisque le tableau a deux dimensions. Nen fournir quune ne veut rien dire. Dailleurs,
laquelle des deux a-t-on fourni ici ? Mystre.

Exercice 28
Voici un exercice intressant.
Dbarrassons-nous dun point sans importance : je suppose que je relve les tempratures au degr prs. Je manipule donc des entiers. Si vous alliez au demi-degr prs, vous
utiliseriez des rels mais cela ne change strictement rien notre propos.
Dans une anne, nous avons 365 jours. Enfin parfois, cest 366. Bien entendu, il faut
prvoir tous les cas et prendre le plus dfavorable. Nous aurons donc besoin de stocker
366 valeurs (une tant parfois inutilise).
23
8 3987 TC PA 00

Squence 3

La premire ide est de dfinir un tableau temp (pour temprature) une dimension :
var
temp : tableau[366] dentiers
Ce tableau permet de stocker les tempratures. Mais est-il pratique demploi ? Pas du
tout ! Il ne rpond pas mon attente : comment rcuprer les tempratures de fvrier ?
celles de lhiver ? Il me faudrait connatre les indices de chaque jour. Or, si je sais que
lhiver dbute le 23 dcembre, je ne sais pas quel est le rang de ce jour (entre 1 et 366).
La dfinition dun tableau doit toujours tre faite srieusement et en fonction de lusage
futur. Dans notre cas, je souhaite pouvoir distinguer les mois. Il est donc beaucoup plus
raisonnable de dfinir un tableau deux dimensions, la premire reprsentant le jour
et lautre le mois.
var
temp : tableau [31,12] dentiers
La temprature du 17 fvrier est stocke dans temp[17,2].
Notez que lon retrouve le problme de lanne bissextile : comme certains mois ont 31
jours, il faut rserver 31 valeurs pour chacun. Pour ceux 28 ou 30 jours, tant pis nous
aurons des lments inutilises (par exemple temp[30,2]). Mais bon, on gaspille 31*12366 soit 6 lments, ce qui est trs peu. Et, de toute faon, on na pas le choix.

Exercice 29
Le problme pos par la boucle est celui dj voqu dans lexercice prcdent : tout
tableau est rectangulaire (toutes les lignes ont le mme nombre dlments). Or, nos mois
nont pas tous autant de jours : certains en ont 30, dautres 31 et un en a 28 ou 29.
Ainsi, faire une boucle de 1 31 nira pas pour les mois de 30 jours : on prendra en
compte un lment du tableau nayant aucune valeur dfinie.
Se limiter une boucle de 1 30 nest pas plus efficace car on ne prendra pas en compte
le dernier jour des mois qui en comptent 31.
Lide est donc de faire une boucle allant de 1 NbrJours(i), i tant le mois considr.
NbrJours est alors une fonction ; si on veut en faire un tableau, on crira NbrJours[i].

Exercice 30
En entre, la fonction a besoin du numro de mois dont on veut connatre le nombre de
jours. Elle renvoie le nombre en question.
Le plus simple est dutiliser un selon cas.

Ne confondez pas les tempratures de fvrier avec la temprature de Fvrier. Merci.


24
8 3987 TC PA 00

Tableaux, structures et types

fonction NbrJours (NumMois : entier) : entier


dbut
selon NumMois
cas 2 : Retourner (28)
cas 4, 6, 9, 11 : Retourner (30)
cas sinon : Retourner (31)
fin selon
fin

Exercice 31
Nous avons besoin dun tableau une dimension et 12 lments (llment dindice i
contenant le nombre de jours du mois i).
var
NbrJours : tableau[12] dentiers
Pour initialiser ce tableau, il faut une procdure recevant le tableau non initialis et le
retournant initialis. On passe donc le paramtre tableau par adresse.
procdure InitNbrJours (var t : tableau[12] dentiers)
var
NumMois : entier
dbut
pour NumMois de 1 12
selon NumMois
cas 2 : t[NumMois] := 28
cas 4, 6, 9, 11 : t[NumMois] := 30
cas sinon : t[NumMois] := 31
fin selon
fin pour
fin
Notez au passage que je viens dcrire un sous-programme autonome. Je peux maintenant le placer dans un programme quelconque pour men servir.

Exercice 32
Le sous-programme sera une fonction puisque je souhaite rcuprer un rsultat (qui sera
un rel). Les valeurs en entre seront le tableau contenant les tempratures et le numro
du mois souhait, toutes par valeur.

25
8 3987 TC PA 00

Squence 3

fonction TempMoyenneMois (t : tableau[31,12] dentiers, Mois : entier) : rel


var
Jour, Cumul : entier
dbut
Cumul := 0
pour Jour de 1 NbrJours(Mois)
Cumul := Cumul + t[Jour,Mois]
fin pour
Retourner (Cumul/NbrJours(Mois))
fin
Voici comment nous appellerons cette fonction :
Saisir "Quel mois voulez-vous tudier ? ", m
Affichage "Moyenne du mois demand : ", TempMoyenneMois(Temp, m)
Temp est le tableau dfini dans lexercice 28.

Arriv en seconde anne, la difficult est ventuellement len-tte de la fonction, mais


surtout pas le calcul de la moyenne. (Enfin, jespre !)

Exercice 33
Le sous-programme sera une fonction puisque je souhaite rcuprer un rsultat (rel).
Les valeurs en entre seront le tableau contenant les tempratures, celui contenant le
nombre de jours par mois et le numro du mois souhait.
Ces trois paramtres sont toutes les informations ncessaires au sous-programme.
Aucune variable globale nest ncessaire. Cela permet dutiliser cette fonction partout
o on le dsire.
fonction TempMoyenneMois (t : tableau[31,12] dentiers,
NbrJours : tableau[12] dentiers,
Mois : entier) : rel
var
Jour, Cumul : entier
dbut
Cumul := 0
pour Jour de 1 NbrJours[Mois]
Cumul := Cumul + t[Jour,Mois]
fin pour
Retourner (Cumul/NbrJours[Mois])
fin
Voici comment nous appellerons cette fonction (on suppose que les tableaux Temp et
TNbrJ sont dfinis correctement).
InitNbrJours (TNbrJ) // exercice 31
Saisir "Quel mois voulez-vous tudier ? ", m
Affichage "Moyenne du mois demand : ", TempMoyenneJours (Temp, TNbrJ, m)

26
8 3987 TC PA 00

Tableaux, structures et types

Exercice 34
Il ny a pas de difficult particulire.
type Client = structure
NumClient : entier
NomClient : chane
PrnomClient : chane
AdrClient : chane
TlClient : chane
DateClient : date
fin structure

Exercice 35
Voir la suite du cours.

Exercice 36
Avec une procdure (la structure est videmment passe par adresse).
procdure InitClient (var C : Client)
dbut
saisir "Entrez le numro : ", C.NumClient
saisir "Entrez le nom : ", C.NomClient
saisir "Entrez le prnom : ", C.PrnomClient
saisir "Entrez ladresse : ", C.AdrClient
saisir "Entrez le tlphone : ", C.TlClient
saisir "Entrez la date de premire commande : ", C.DateClient
fin
Voici comment on sen sert :
var
Cl : Client

InitClient (Cl)

27
8 3987 TC PA 00

Squence 3

Avec une fonction :


fonction InitClient : Client
var
Cl : Client
dbut
saisir "Entrez le numro : ", Cl.NumClient
saisir "Entrez le nom : ", Cl.NomClient
saisir "Entrez le prnom : ", Cl.PrnomClient
saisir "Entrez ladresse : ", Cl.AdrClient
saisir "Entrez le tlphone : ", Cl.TlClient
saisir "Entrez la date de premire commande : ", Cl.DateClient
Retourner (Cl)
fin
Notez bien lastuce : on cre une variable temporaire Cl que lon retourne en rsultat.
La variable Cl sera supprime ds que lon quittera la fonction mais le rsultat est prserv.
Vous remarquerez que cette fonction ne possde aucun paramtre. Voici comment on
sen sert :
var
Client1 : Client

Client1 := InitClient()
Certains langages proposent de mettre des parenthses vides pour bien montrer que lon
fait un appel de fonction sans paramtre. Je conserve cette notation car ne pas mettre
de parenthses pourrait faire croire que InitClient est une variable.

Exercice 37
Voici le tableau et sa variable :
var
ge : tableau[40] dentiers
Nbrges : entier
Le sous-programme sera forcment une procdure car nous devons modifier deux variables : le tableau et la variable contenant son nombre dlments. Les deux seront passes
par adresse.
Autre difficult, comment renvoyer des valeurs alatoires entre 18 et 23 ans ? Et bien, il
suffit de rsoudre une inquation :
0
18

alatoire (i)

i-1, soit :

alatoire (i) +18

(i-1) + 18

Or, on veut une borne maximale de 23, soit (i-1)+18 = 23 soit i = 6.

28
8 3987 TC PA 00

Tableaux, structures et types

Au final :
18

alatoire (6) +18

23

Nous avons notre formule. Voici le sous-programme :


procdure InitAlat35 (var t : tableau[40] dentiers, var NbrT : entier)
var
i : entier
dbut
pour i de 1 35
t[i] := alatoire(6)+18
fin pour
NbrT := 35
fin
Pour initialiser mes variables, jcrirai :
InitAlat35 (ge, Nbrges)

Exercice 38
Le sous-programme sera une fonction prenant en entre le tableau et son nombre dlments et retournant la valeur moyenne. Les paramtres sont passs par valeur car on ne
souhaite pas les modifier.
fonction MoyenneTab (t : tableau[40] dentiers, NbrT : entier) : rel
var
Somme : entier
dbut
Somme := 0
pour i de 1 NbrT
Somme := Somme + t[i]
fin pour
Retourner (Somme/NbrT)
fin

Exercice 39
La dclaration ne doit poser aucune difficult :
type
Tableauge = structure
lment : tableau[40] dentiers
Nbrlments : entier
fin structure
(Les noms sont un peu arbitraires.)

29
8 3987 TC PA 00

Squence 3

Je dclare ensuite une variable :


var
Bts1 : Tableauge
Cette variable Bts1 correspond logiquement ma classe de BTS 1re anne.
Pour accder un lment du tableau, voir la suite du cours.

Exercice 40
Il ne faut pas confondre le type et la variable. Le type Tableauge est un concept abstrait, comme la notion dentier. Ce type ne contient donc pas de valeur, de tableau ou de
variable. Il dit juste quune variable de ce type contiendra un tableau de quarante entiers
appel lment et un entier appel Nbrlments.
Le tableau lment ne peut donc appartenir qu une variable de type Tableauge.
Rciproquement, toute variable de type Tableauge contient un tableau lment.
Vu mon sujet, il est vident que je fais rfrence au tableau lment de la variable Bts1
(de type Tableauge).

Exercice 41
Voici les deux sous-programmes. Voyez bien lintrt de la structure : nous navons plus
quune seule variable en paramtre. Jai mis les changements en gras.
procdure InitAlat35 (var Classe : Tableauge)
var
i : entier
dbut
pour i de 1 35
Classe.lment[i] := alatoire(6)+18
fin pour
Classe.Nbrlments := 35
fin
fonction MoyenneTab (Classe : Tableauge) : rel
var
Somme : entier
dbut
Somme := 0
pour i de 1 Classe.Nbrlments
Somme := Somme + Classe.lment[i]
fin pour
Retourner (Somme/Classe.Nbrlments)
fin
Si Bts1 est de type Tableauge, nous utiliserons ces sous-programmes ainsi :
InitAlat35 (Bts1)
Afficher MoyenneTab(Bts1)
30
8 3987 TC PA 00

Tableaux, structures et types

Exercice 42
Il ne doit pas y avoir de difficult. Je reprends tous les types dont jai besoin :
type
Client = structure
NumClient : entier
NomClient : chane
PrnomClient : chane
AdrClient : chane
TlClient : chane
DateClient : date
fin structure
TabClient = structure
lment : tableau[1000] de Client
NbrClients : entier
fin structure
Notez que jenchane les dclarations de types aprs le mot cl type, de mme que lon
enchane les dclarations de variables aprs le mot cl var.
Je me limite 1 000 clients car le sujet prcise que je nirai pas au-del.

Exercice 43
Le sous-programme sera une procdure puisquil sagit dafficher des informations, pas
de renvoyer un rsultat.
Le principe est simple : je parcours le tableau du premier au dernier lment (que lon
connat par NbrClients) et jaffiche le champ NomClient de chaque lment.
procdure AffichageNom (TC : TabClient)
var
i : entier
dbut
pour i de 1 TC.NbrClients
Afficher TC.lment[i].NomClient
fin pour
fin
Expliquons le code :
dans la structure TC, je veux accder au tableau, donc TC.lment ;
partir du tableau, je veux llment i, soit TC.lment[i]. Notez bien que
TC.lment[i] fait rfrence une variable de type Client ;
dans la variable structure TC.lment[i], je souhaite obtenir le nom. Jcrirai alors
TC.lment[i].NomClient.
Finalement, TC est une structure contenant un tableau de structures.

31
8 3987 TC PA 00

Travaux dirigs 1

Exercice 1
Nous aurons une fonction prenant en paramtre par valeur une structure de type TabClient
et retournant un entier.
Le principe de lalgorithme est simple : on va du premier au dernier lment du tableau et
on incrmente une variable initialement nulle chaque fois que lon rencontre un client
habitant Aubusson.
Aller du premier au dernier lment dun tableau impose lemploi dune boucle pour.
Noubliez pas que le nombre dlments est stock dans le champ NbrClients.
fonction Aubusson (TC : TabClient) : entier
var
Nbr, i : entier
dbut
Nbr := 0
pour i de 1 TC.NbrClients
si TC.lment[i].AdrClient = "Aubusson"
alors
Nbr := Nbr + 1
fin si
fin pour
Retourner (Nbr)
fin
Notez bien laccs au champ AdrClient : dans la structure TC, je veux accder au tableau (donc
TC.lment), dans le tableau, llment i (donc TC.lment[i]) et, dans cet lment qui est une
variable de type Client, jaccde au champ voulu, soit TC.lment[i].AdrClient.
Comment passer de la fonction Aubusson un sous-programme plus gnral fonctionnant
avec nimporte quelle ville ? Il suffit de passer la ville en paramtre ! (En gras ce qui change.)
fonction NbrVille (TC : TabClient, Ville : chane) : entier
var
Nbr, i : entier
Ok ? Jutilise le paramtre

dbut
Nbr := 0
pour i de 1 TC.NbrClients
si TC.lment[i].AdrClient =
alors
Nbr := Nbr + 1
fin si
fin pour
Retourner (Nbr)
fin

Ville

retenir : Parcours dun tableau du dbut la fin

boucle pour.

33
8 3987 TC PA 00

Exercice 2
Dans tous les cas, le sous-programme sera une fonction prenant en paramtre une structure
de type TabClient et le numro du client cherch et retournant une chane de caractres (soit
un rsultat du type du champ NomClient).
Len-tte sera :
fonction RechercheClient (TC : TabClient, Numro : entier) : chane
Quelle diffrence aurons-nous dans lalgorithme selon que le client existe forcment ou
non ? Voici le principe des algorithmes dans les deux cas :
si le client existe, nous parcourrons le tableau jusqu ce quon le trouve ;
si le client peut ne pas exister, nous le parcourrons jusqu le trouver ou arriver en fin
de tableau.
Dans les deux cas, on utilise une boucle tant que.
Le client existe
fonction RechercheClient (TC : TabClient, Numro : entier) : chane
var
i : entier
dbut
i=1
tant que TC.lment[i].NumClient <> Numro faire
i := i+1
fin tant que
Retourner (TC.lment[i].NomClient)
fin
Comprenez bien cet algorithme : avec la variable i servant dindice de tableau, on va se positionner sur le client voulu (tant que lon nest pas sur le bon client, on avance dun lment).
Notez que je ne me proccupe pas du nombre dlments du tableau car je suis certain de
trouver ce que je cherche.
On sort de la boucle tant que quand le test est faux, soit quand TC.lment[i].NumClient <>
Numro est faux, donc quand TC.lment[i].NumClient = Numro.
Je peux initialiser directement le rsultat puisque je sais que je suis sur le bon lment.
Le client nexiste pas forcment
Lalgorithme prcdent nest plus acceptable. En effet, si le client cherch nexiste pas, la
boucle continuera indfiniment. force daugmenter, lindice i va sortir du tableau. Cela
posera de gros problmes !
Je suis donc oblig de rajouter une condition dans ma boucle : elle sarrte lorsque je trouve
le bon lment ou lorsque je suis la fin du tableau.

34
8 3987 TC PA 00

Voici la nouvelle boucle :


tant que TC.lment[i].NumClient <> Numro et i < TC.NbrClients faire
i := i+1
fin tant que
Vrifions quelle fonctionne bien, savoir que je ne dpasse jamais le dernier lment du
tableau.
Je me positionne sur le premier, puis le deuxime jusqu lavant-dernier lment du
tableau (en supposant videmment que je naie toujours pas trouv mon lment).
Sur lavant-dernier lment, mon test est toujours vrai (i vaut TC.NbrClients-1). Jincrmente
donc i qui vaut TC.NbrClients. Je suis alors sur le dernier lment du tableau. Dans ce cas,
mon test est systmatiquement faux (i nest plus infrieur TC.NbrClients) donc je sors de la
boucle.
Finalement, je peux sortir de la boucle dans trois cas :
jai trouv mon client (TC.lment[i].NumClient = Numro) ;
je suis sur le dernier lment du tableau (i = TC.NbrClients) et je nai pas trouv mon
client ;
je suis sur le dernier lment du tableau et il contient le client que je cherche.
Tout cela pour dire que je peux sortir de la boucle pour deux raisons totalement diffrentes :
car jai trouv mon client ou parce que jai atteint la fin du tableau sans le trouver.
Je vais donc devoir rajouter un test pour vrifier dans quelle situation je suis.
si TC.lment[i].NumClient = Numro
alors
Retourner (TC.lment[i].NomClient)
sinon
Retourner ("")
fin si
Pour que le programme appelant mon sous-programme sache interprter le rsultat, je
prends la convention suivante :
si le client nexiste pas, je renvoie une chane vide ;
sil existe, je renvoie son nom.
Comme un client porte forcment un nom, il ny aura aucune ambigut. Le programme
appelant testera le rsultat et sadaptera en consquence.

35
8 3987 TC PA 00

Voici la fonction finale (en gras ce qui a chang) :


fonction RechercheClient (TC : TabClient, Numro : entier) : chane
var
i : entier
dbut
i=1
tant que TC.lment[i].NumClient <> Numro et i < TC.NbrClients faire
i := i+1
fin tant que
si TC.lment[i].NumClient = Numro
alors
Retourner (TC.lment[i].NomClient)
sinon
Retourner ("")
fin si
fin
Notez quaprs la boucle, je teste lexistence de llment et non larrive en fin de tableau.
Pourquoi ? Car cest la premire condition qui lemporte. Si je suis en fin de tableau (sur le
dernier lment) et que ce dernier lment est celui que je cherchais, je suis dans la situation
o je lai trouv.
La fonction est nettement plus longue et technique : il faut prendre son temps et vrifier,
comme nous lavons fait, que le test est correct.
Sans prcision sur lexistence du client
Il faut toujours prendre le cas gnral ( savoir le plus dfavorable). Sans indication dans un
sujet, vous devez estimer que llment cherch nest pas forcment prsent.
retenir :
parcours dun tableau pour chercher un lment boucle tant que ;
si llment nest pas forcment prsent, il faut tester larrive en fin de tableau
dans la boucle puis, en sortie de boucle, tester si lon est sorti car on avait trouv
llment ou parce que lon tait en fin de tableau.

Exercice 3
Le client le plus ancien (ou le plus machin, ou le moins truc) existe toujours. De plus, il faut
parcourir tout le tableau pour tre sr de le trouver.
On est donc face un mlange des deux exercices prcdents. On utilisera une boucle pour
afin de parcourir tout le tableau.
Le principe sera le suivant : on va dire que le premier client est le plus ancien (temporairement). On va ensuite parcourir tout le tableau, du deuxime au dernier lment. On comparera successivement le client courant avec celui temporairement le plus ancien. Si le client
courant est plus ancien, il devient celui temporairement le plus ancien. Et cela jusquau bout.
En fin de parcours, le client temporairement le plus ancien est rellement le plus ancien.

36
8 3987 TC PA 00

Pour obtenir le sens de la comparaison (encore une erreur classique !), il faut rflchir : le
client le plus ancien est celui qui a la date la plus ancienne, soit la plus petite.
Deux solutions pour renvoyer le rsultat : soit on retourne lindice du client le plus ancien,
soit le client lui-mme. Nous allons voir les deux solutions.
Premire solution, on retourne lindice.
fonction PlusAncien (TC : TabClient) : entier
var
IndiceClAncien, i : entier
dbut
IndiceClAncien := 1
pour i de 2 TC.NbrClients
si TC.lment[i].DateClient < TC.lment[IndiceClAncien].DateClient
alors
IndiceClAncien := i
fin si
fin pour
Retourner (IndiceClAncien)
fin
Comprenez bien loptimisation : la boucle commence lindice 2 puisquau dbut, on estime
que cest le premier lment qui est le plus ancien. Commencer la boucle lindice 1 reviendrait comparer le premier lment lui-mme, ce qui ne sert rien.
Deuxime solution, on retourne le client. Du coup, notre variable temporaire sera un client
et non plus un entier (en gras ce qui change)
fonction PlusAncien (TC : TabClient) : Client
var
ClAncien : Client
i : entier
dbut
ClAncien := TC.lment[1]
pour i de 2 TC.NbrClients
si TC.lment[i].DateClient < ClAncien.DateClient
alors
ClAncien := TC.lment[i]
fin si
fin pour
Retourner (ClAncien)
fin

37
8 3987 TC PA 00

retenir : recherche dun lment le plus machin ou le moins truc on utilise une variable stockant le plus truc ou le moins machin courant. Au dbut, on estime que cest le
premier lment puis, avec un pour allant de lindice 2 la fin, on compare chaque lment avec notre variable. Si llment courant est plus truc ou moins machin que notre
variable, il devient notre nouvelle variable.

Exercice 4
Pour ajouter un lment un tableau, il faut 2 choses : un tableau et un lment ajouter.
Le sous-programme, une procdure, aura deux paramtres : la structure de type TabClient
passe par adresse car modifie (on ajoute un lment) et une variable de type Client (le
client ajouter, pass par valeur car il nest pas modifi).
Attention ne pas passer en paramtre lindice o ajouter le client. En effet, le tableau des
clients nest pas tri (sil lavait t, on laurait mentionn explicitement dans le sujet). Dans
ce cas, on peut mettre notre nouveau client nimporte o puisque aucun ordre particulier
nest demand. Nous ferons au plus simple en le mettant dans le premier lment disponible,
soit en fin de tableau : si le tableau possde actuellement NbrClients lments, le premier
lment libre est le NbrClients+1e (sil y a dix lments, le onzime est disponible).
Il ne faut pas oublier dincrmenter NbrClients pour indiquer que le tableau comporte un
nouvel lment. Cela donne la procdure qui suit.
procdure Insre (var TC : TabClient, Cl : Client)
dbut
TC.lment[TC.NbrClients+1] := Cl
TC.NbrClients := TC.NbrClients + 1
fin
Cest court, nest-ce pas ? Il ne fallait surtout pas samuser crire ceci :
TC.lment[TC.NbrClients+1].NumClient := Cl.NumClient
TC.lment[TC.NbrClients+1].NomClient := Cl.NomClient

TC.lment[TC.NbrClients+1].DateClient := Cl.DateClient
Bref, inutile daffecter les champs un par un. Je vous rappelle la smantique de laffectation
(revoir squence 1, paragraphes 3D5 et 3F1). Les deux seules contraintes sont que :
1. gauche de loprateur daffectation figure une variable.
2. La variable et lexpression de droite doivent tre de mme type.
Ces deux contraintes sont vrifies. On affecte bien un client un autre client. Notez en passant la puissance de loprateur daffectation : on peut affecter en une ligne une structure
de tableaux de structures de tableaux
Enfin, on pourrait prvoir un message derreur (et un arrt du programme) si le tableau tait
plein, rendant lajout impossible. Mais lhypothse de dpart (1 000 clients maximum) doit
empcher tout dbordement.

38
8 3987 TC PA 00

retenir : ajout dun lment dans un tableau non tri


on lajoute la fin
et on noublie pas dincrmenter la variable mmorisant le nombre dlments.
Le sujet indiquera (parfois implicitement) sil faut vrifier ou non quil reste de la place
dans le tableau.

Exercice 5
Pour supprimer le dernier client, il suffit de dire que jen ai un de moins ! Je laisse en ltat
le contenu de llment correspondant car la case est rpute vide et cest cela qui compte.
La structure doit tre passe par adresse puisquon la modifie. Cela donne :
procdure SupprimeDernier (var TC : TabClient)
dbut
TC.NbrClients := TC.NbrClients-1
fin

Exercice 6
Le premier sous-programme est vite fait, on reprend celui de lexercice 2 sauf que lon renvoie lindice et plus le nom. Jai mis en gras les modifications.
fonction RechercheClient (TC : TabClient, Numro : entier) : entier
var
i : entier
dbut
i=1
tant que TC.lment[i].NumClient <> Numro et i < TC.NbrClients faire
i := i+1
fin tant que
si TC.lment[i].NumClient = Numro
alors
Retourner (i)
sinon
Retourner (0)
fin si
fin
Notez que lon part du principe que le client nexiste pas forcment. Si je ne le trouve pas, je
renvoie 0, sachant que cette valeur nest pas un indice valide. Jvite donc toute ambigut.
Pour la suppression, il suffit dappliquer la technique donne dans le sujet. La structure est
passe par adresse puisquon la modifie.

39
8 3987 TC PA 00

Il faut nanmoins vrifier que llment existe. Si ce nest pas le cas, ma procdure ne fait
rien (on pourrait envisager un message derreur ou autre).
procdure Supprimer (var TC : TabClient, Numro : entier)
var
i, IndiceASupprimer : entier
dbut
IndiceASupprimer := RechercheClient (TC, Numro)
si IndiceASupprimer > 0
alors
pour i de IndiceASupprimer TC.NbrClients-1
TC.lment[i] := TC.lment[i+1]
fin pour
TC.NbrClients := TC.NbrClients-1
fin si
fin
Notez que jaffecte toujours directement un client un autre donc un lment du tableau
un autre. Inutile de travailler champ champ !
Vrifiez que vous comprenez bien les deux bornes de la boucle pour et assurez-vous que jai
appliqu lalgorithme donn dans le sujet.
retenir : suppression dun lment
on lcrase en dcalant tous ceux qui sont sa
droite dune case vers la gauche, sans oublier de dcrmenter la variable mmorisant le
nombre dlments.

Exercice 7
Les exercices prcdents nous font parcourir tout le tableau pour chercher un lment
donn. Si le tableau possde des milliers dlments, ce peut tre trs long.
Avec un tableau tri, on utilise la recherche dichotomique infiniment plus rapide. videmment,
cela ne fonctionne que si lon cherche en fonction du tri : si mon tableau de clients est tri
daprs le numro de client NumClient, je devrai faire un parcours squentiel (du dbut la
fin) pour trouver un client daprs son nom.
Le seul inconvnient du tableau tri, cest que lajout dun lment ne peut plus se faire la
fin du tableau : il faut linsrer la bonne place, ce qui oblige dcaler des lments.
Nous allons voir tout cela.

Exercice 8
Pour permuter deux clients, jai besoin de deux paramtres passs par adresse dans ma procdure. Passer en paramtre le tableau et les deux indices serait beaucoup moins souple.

40
8 3987 TC PA 00

procdure changeClient (var Cl1 : Client, var Cl2 : Client)


var
Cl3 : Client
dbut
Cl3 := Cl1
Cl1 := Cl2
Cl2 := Cl3
fin
Lalgorithme dchange est toujours le mme, quel que soit le type des donnes changes.
Pour rechercher le plus petit lment dun tableau, on va sappuyer sur lalgorithme de
lexercice 3 renvoyant lindice. Les deux diffrences :
1. On recherche le plus petit selon NumClient et non plus DateClient (changement trivial).
2. En paramtre, on doit passer lindice de llment partir duquel on commence la
recherche.
Jai mis en gras ce qui change par rapport lexercice 3. Par cohrence, jai renomm la variable IndiceClAncien en IndiceClPetit. Cela nest pas en gras.
fonction PlusPetit (TC : TabClient, IndiceDpart : entier) : entier
var
IndiceClPetit, i : entier
dbut
IndiceClPetit := IndiceDpart
pour i de IndiceDpart+1 TC.NbrClients
si TC.lment[i].NumClient < TC.lment[IndiceClPetit].NumClient
alors
IndiceClPetit := i
fin si
fin pour
Retourner (IndiceClPetit)
fin
Le sous-programme de tri est simple crire maintenant que nous avons les deux prcdents.
La structure contenant le tableau est passe par adresse puisquon va modifier ce dernier.
procdure tri (var TC : TabClient)
var
i : entier
dbut
pour i de 1 TC.NbrClients-1
changeClient (TC.lment[i], TC.lment[PlusPetit(TC, i)])
fin pour
fin

41
8 3987 TC PA 00

Comprenez bien cet algorithme : il est assez optimis. Une version moins lgante mais plus lisible consiste utiliser une variable intermdiaire IndicePlusPetit (je ne redonne que la boucle) :
pour i de 1 TC.NbrClients-1
IndicePlusPetit := PlusPetit(TC, i)
changeClient (TC.lment[i], TC.lment[IndicePlusPetit])
fin pour
Dans tous les cas, vous voyez qu litration i, on permute la ie case du tableau avec llment le plus petit parmi ceux se situant de lindice i au dernier lment.
Dans les deux cas, les paramtres passs changeClient sont bien des clients.
retenir : pour trier un tableau, il faut connatre une mthode ( bulles ou par insertion,
cela na pas dimportance).

Exercice 9
Le sous-programme (fonction) peut renvoyer lindice ou directement le client cherch, au
choix. Jopte pour lindice.
En entre, on aura dune part la structure contenant le tableau et dautre part la valeur du
numro cherch.
fonction Recherche (TC : TabClient, Numro : entier) : entier
var
Initial : entier
Final : entier
Milieu : entier
dbut
Initial := 1
Final := TC.NbrClients
rpter
Milieu := (Initial + Final) div 2
si TC.lment[Milieu].NumClient > Numro
alors
Final := Milieu-1
sinon
Initial := Milieu+1
fin si
jusqu (TC.lment[Milieu].NumClient = Numro) ou (Initial > Final)
si TC.lment[Milieu].NumClient = Numro
alors
Retourner (Milieu)
sinon
Retourner (-1)
fin
fin

42
8 3987 TC PA 00

Notez loprateur div qui effectue la division entire comme annonc dans le sujet. En effet,
les indices sont des nombres entiers, pas des rels. On pouvait galement utiliser la fonction
int prenant un rel et renvoyant un entier : int ((Initial + Final)/2).
La boucle rpter peut se terminer pour deux raisons : soit parce que llment est trouv,
soit parce que llment nest pas trouv (soyez sr de bien comprendre la condition darrt
dans ce cas). Il est donc indispensable de tester aprs la boucle pourquoi on est sorti comme
nous lavions dj fait dans lexercice 2.
Je renvoie la valeur -1 si llment nest pas trouv (aucune ambigut avec une valeur dindice valide).
retenir : rechercher un lment dans un tableau tri

dichotomie.

Exercice 10
Recherche de lindice : parcours squentiel
Le principe est le suivant : on va parcourir le tableau du dbut la fin donc du plus petit
au plus grand lment. Ds que llment courant est suprieur ou gal notre lment
insrer, on a trouv lindice. Reprenons lexemple du sujet :
1

Je veux insrer la valeur 4. Je parcours le tableau : valeurs 1, 2 puis 5. 5 tant suprieur


4, cest bien l que je placerai mon lment en dcalant les lments dindice suprieur ou
gal 3 (donc llment 5 et les suivants).
tudions maintenant les cas extrmes :
si je voulais ajouter la valeur 0, le premier lment du tableau serait dj plus grand.
Cela signifie juste que mon nouvel lment sera le premier. Lalgorithme prcdent
sapplique ;
si je voulais ajouter la valeur 15, aucun lment ne serait plus grand. Il faut donc que
ma boucle de parcours gre le cas o lon sort du tableau sans avoir trouv dlment
plus grand. Dans ce cas, le nouvel lment se place la fin.
Notre sous-programme sera une fonction prenant en paramtre la structure de type
TabClient et la valeur de NumClient de llment insrer. Noubliez pas quici, nous navons
pas un tableau dentiers comme dans lexemple mais un tableau de clients.
fonction RechercheIndiceInsertion (TC : TabClient, Numro : entier) : entier
var
i : entier
dbut
i := 1
tant que (TC.lment[i].NumClient < Numro) et (i < TC.NbrClients)
i := i+1
fin tant que

43
8 3987 TC PA 00

si TC.lment[i].NumClient >= Numro


alors
Retourner (i)
sinon
Retourner (TC.NbrClients+1)
fin si
fin
Expliquons un peu lalgorithme.
Javance dans le tableau tant que je nai pas trouv dlment plus petit et que je ne suis pas
au bout du tableau.
Comme je peux tre sorti de la boucle pour deux raisons (lment trouv ou fin de tableau),
je dois tester aprs la boucle pourquoi je suis sorti (cest la mme chose que dans lexercice
2, cest trs classique).
Si je suis en fin de tableau sans avoir trouv dlment plus grand, cest que mon nouveau client se mettra en fin de tableau, donc dans llment TC.NbrClients+1 sil y en avait
TC.NbrClients.
Un inscrit du CNED ma fait remarquer tout fait justement que jaurais pu mettre i+1 au
lieu de TC.NbrClients+1. Voyez-vous pourquoi ? Parce que, si je nai pas trouv mon lment
et suis en fin de tableau, je suis sorti de la boucle cause de la condition i < TC.NbrClients
devenue fausse. Comme i augmente de 1 en 1, cela signifie que i vaut TC.NbrClients. Les deux
variables sont donc gales. Le problme, cest que pour sen rendre compte, il faut rflchir
comme nous venons de le faire. Mettre i+1 est donc moins explicite que TC.NbrClients+1. Ma
solution est prfrable : un mois aprs, on la comprend toujours immdiatement.
Le dcalage des lments
Cela ne pose pas de difficult. On a besoin en paramtre de notre structure (passe par
adresse puisquon la modifie) et de lindice partir duquel on dcale.
Il faut penser incrmenter le nombre dlments du tableau puisque lon occupera une
case de plus.
procdure Dcalage (var TC : TabClient, Indice : entier)
var
i : entier
dbut
pour i de TC.NbrClients Indice pas -1
TC.lment[i+1] := TC.lment[i]
fin pour
TC.NbrClients := TC.NbrClients+1
fin

44
8 3987 TC PA 00

Le dcalage tant ralis de la gauche vers la droite, il faut commencer par la fin du tableau
(cest le cas symtrique de lexercice 6). Cela nous donne loccasion demployer un pas ngatif
avec une boucle pour.
On pouvait galement dcaler lindice de boucle dun cran :
pour i de TC.NbrClients+1 Indice+1 pas -1
TC.lment[i] := TC.lment[i-1]
fin pour
Vrifiez que cest rigoureusement la mme chose. Vous choisirez la boucle qui vous semble
la plus naturelle.
Linsertion
Il suffit dappeler les deux sous-programmes prcdents. La structure est toujours passe par
adresse. On doit passer par valeur le client ajouter.
procdure Insertion (var TC : TabClient, Cl : Client)
var
Position : entier
dbut
Position := RechercheIndiceInsertion (TC, Cl.NumClient)
Dcalage (TC, Position)
TC.lment[Position] := Cl
fin
Si llment ajouter se place en fin de tableau, aucun dcalage nest ncessaire. Cela nous
pose-t-il problme ? Non, car la boucle pour ne sexcutera pas puisquelle sera du style pour
i de 4 5 pas 1. (Si vous ntes pas convaincu quune telle boucle ne sexcute pas, retournez
en squence 1, paragraphe 5C et apprenez votre cours !)
Vous remarquerez ici lintrt des dcoupages en sous-programmes : munis de la recherche
et du dcalage, nous crivons linsertion trs simplement.
retenir : insertion dun lment dans un tableau tri on recherche la position de
llment puis on dcale les lments situs aprs pour laisser une place au petit nouveau.

45
8 3987 TC PA 00

Travaux dirigs 2

Exercice 1
Structure Train :
type
Train = structure
Numro : entier
Type : chane
NbrPlaces1 : entier
NbrPlaces2 : entier
Provenance : chane
fin structure
Provenance indique la ville de dpart du train.
Le tableau des trains naura pas besoin dtre inclus dans une structure pour stocker son
nombre dlments car le sujet indique prcisment quil y a exactement 95 trains.
Structure Arrive :
type
Arrive = structure
Numro : entier
Dcalage : entier
fin structure
Pour stocker les arrives, nous devons utiliser une structure englobant le tableau des arrives et
une variable indiquant combien darrives sont actuellement dans le tableau. Cela donne :
type
TableauArrives = structure
lment : tableau [10000] dArrives
NbrArrives : entier
fin structure

46
8 3987 TC PA 00

Exercice 2
Moyenne des dcalages de tous les trains
Ce sera une fonction classique.
fonction MoyenneDcalage (TA : TableauArrives) : rel
var
i : entier
Somme : entier
dbut
Somme := 0
pour i de 1 TA.NbrArrives
Somme := Somme + TA.lment[i].Dcalage
fin pour
Retourner (Somme/TA.NbrArrives)
fin
Moyenne, dcalage minimum et maximum
On doit renvoyer trois rsultats donc plus question dutiliser une fonction : il faut une procdure avec ces trois rsultats en paramtre par adresse. Les deux autres paramtres seront
notre structure et le numro du train cherch.
Lalgorithme nest pas trs simple. En effet, quand dans le premier TD (exercice 3) on cherchait
le client le plus ancien, on disait que ctait le premier puis on parcourait le tableau pour vrifier
cela.
Ici, cest un peu diffrent puisque lon ne sintresse pas tous les lments du tableau, mais
seulement ceux qui concernent le train pass en paramtre. De plus, on cherche en mme
temps les deux dcalages extrmes. On reprendra donc lalgorithme de lexercice 3 en le
modifiant pour prendre cela en compte :
le premier lment, qui est notre plus petit ou plus grand temporaire, ne sera pas le
premier du tableau, mais le premier concernant le train cherch. Il nous faut donc une
boucle pour y arriver ;
ensuite, on ne prendra pas en compte tous les lments, mais seulement ceux du train
cherch. On fera donc une boucle sur tous les lments restants (boucle pour) en ne
sarrtant que sur les arrives de notre train (avec un si) ;
chaque lment concern devra donner lieu vrification avec nos deux dcalages extrmes ;
il faudra compter combien darrives du train cherch nous avons pour calculer la moyenne.
Je vous rappelle que nous supposons que le train existe forcment.

47
8 3987 TC PA 00

Lalgorithme est prsent ci-dessous.


procdure StatTrain (TA : TableauArrives, Numro : entier, var Min : entier,
var Max : entier, var Moy : rel)
var
i : entier
j : entier
NbrArrives : entier
dbut
// on cherche la premire arrive du train Numro
i := 1
tant que TA.lment[i].Numro <> Numro faire
i := i+1
fin tant que // comme le train existe, on est certain que la boucle sarrte
// nous sommes positionns sur la premire arrive du train Numro
NbrArrives := 1
Min := TA.lment[i].Dcalage // cette variable est le paramtre par adresse
Max := TA.lment[i].Dcalage // idem
Moy := TA.lment[i].Dcalage // idem
// on va parcourir le tableau jusqu la fin et
// sarrter sur toutes les arrives du train Numro
pour j de i+1 TA.NbrArrives
si TA.lment[j].Numro = Numro
alors
NbrArrives := NbrArrives + 1
Moy := Moy + TA.lment[j].Dcalage
si TA.lment[j].Dcalage < Min
alors
Min := TA.lment[j].Dcalage
sinon
si TA.lment[j].Dcalage > Max
alors
Max := TA.lment[j].Dcalage
fin si
fin si
fin si
fin pour
Moy := Moy/NbrArrives
fin
Notez la boucle pour avec lindice j : nous sommes obligs dutiliser un nouvel indice : pas
question dcrire pour i de i+1

48
8 3987 TC PA 00

Exercice 3
Comme le train nexiste pas forcment, il faudra vrifier nos sorties de boucle. De plus, et cest
difficile, il faut indiquer au programme appelant si la recherche a t ou non fructueuse.
Lorsque nous recherchions un lment dans un tableau, nous pouvions renvoyer 0 en cas
dabsence puisque cette valeur ne pouvait pas tre confondue avec un indice rel. Ce nest
pas possible avec une valeur minimale, maximale ou moyenne : toute valeur (mme la plus
grande ou la plus petite) est plausible.
Comment sen sortir ? Nous allons transformer notre procdure en fonction. La fonction
renverra un boolen : vrai si la recherche a abouti, faux sinon.
Retenez bien cette technique, elle est trs classique !
Attention, la solution habituelle de ltudiant tte en lair, consistant afficher un message
davertissement ( Train non trouv ), est totalement errone : le sous-programme sadresse
au programme appelant, pas lutilisateur (revoyez la squence 2, paragraphe 1B). Cest
donc le programme appelant quil faut avertir.
Voici ce que cela donne :
fonction StatTrain (TA : TableauArrives, Numro : entier, var Min : entier,
var Max : entier,var Moy : rel) : boolen
var
i : entier
j : entier
NbrArrives : entier
dbut
// on cherche la premire arrive du train Numro
// le train peut ne pas exister -> attention ne pas sortir du tableau !
i := 1
tant que (TA.lment[i].Numro <> Numro) et (i < TA.NbrArrives) faire
i := i+1
fin tant que
// pourquoi sommes-nous sortis ? Arrive trouve ou fin de tableau ?
si TA.lment[i].Numro <> Numro
alors // fin de tableau sans avoir trouv notre arrive
Retourner (faux)

Cest une mtaphore polie pour parler de ceux qui napprennent pas correctement leur cours.

49
8 3987 TC PA 00

sinon // nous sommes positionns sur la premire arrive du train Numro


// ce qui suit est identique au sous-programme prcdent
NbrArrives := 1
Min := TA.lment[i].Dcalage // cette variable est le paramtre par adresse
Max := TA.lment[i].Dcalage // idem
Moy := TA.lment[i].Dcalage // idem
// on va parcourir maintenant la fin du tableau et
// sarrter sur toutes les arrives de Numro
pour j de i+1 TA.NbrArrives
si TA.lment[j].Numro = Numro
alors
NbrArrives := NbrArrives + 1
Moy := Moy + TA.lment[j].Dcalage
si TA.lment[j].Dcalage < Min
alors
Min := TA.lment[j].Dcalage
sinon
si TA.lment[j].Dcalage > Max
alors
Max := TA.lment[j].Dcalage
fin si
fin si
fin si
fin pour
Moy := Moy/NbrArrives
Retourner (vrai)
fin si
fin
Lalgorithme ntait pas si difficile condition de bien faire attention aux diffrentes situations rencontres.

Exercice 4
Je vous propose lalgorithme suivant : nous allons parcourir le tableau des arrives du dbut
la fin. Pour chaque train arriv en retard (Dcalage > 0), nous irons vrifier si cest un TGV.
Dans laffirmative, nous incrmenterons un petit compteur.
Les trains qui arrivent (qui sont dans le tableau des arrives) sont dans le tableau des 95
trains. Cest une remarque importante car elle simplifie grandement notre recherche du
train : on est sr quil existe.

50
8 3987 TC PA 00

Voici lalgorithme :
fonction NbrTVGRetard (TA : TableauArrives, Trains : tableau[95] de Train) : entier
var
i : entier
j : entier
Nbr : entier
dbut
Nbr := 0
pour i de 1 TA.NbrArrives
si TA.lment[i].Dcalage > 0
alors
// Train en retard TGV ?
// 1 tape : cherchons ce train
j := 1
tant que Trains[j].Numro <> TA.lment[i].Numro faire
j := j + 1
fin tant que
// arriv ici, on a trouv le train.
// 2 tape : est-il un TGV ?
si Trains[j].Type = "TGV"
alors
Nbr := Nbr + 1
fin si
fin si
fin pour
Retourner (Nbr)
fin
Cet algorithme est assez complexe puisquil gre deux boucles imbriques sur deux tableaux
diffrents. De plus, la boucle imbrique est une recherche dlment, algorithme trs classique dont nous aurons certainement besoin pour dautres recherches.
Ces deux remarques (complexit et besoin ultrieur prvisible) militent pour la dnition
dune fonction indpendante charge de chercher un train donn. Dune part, cela simpliera
lalgorithme prcdent et dautre part, vous pourrez appeler cette fonction dans dautres
sous-programmes.
Comme nous voulons une fonction de recherche utilisable par dautres sous-programmes,
nous devons lcrire la plus gnrale possible. Il faut donc tester le cas o le train nest pas
prsent, mme si dans le sous-programme actuel on sait quil est l.
Cest sufsamment important pour faire lobjet de lexercice suivant.

51
8 3987 TC PA 00

Exercice 5
La fonction de recherche est classique. On renvoie lindice 0 si on ne trouve pas le train.
fonction RechercheTrain (Trains : tableau[95] de Train, Numro : entier) : entier
var
i : entier
dbut
i := 1
tant que (Trains[i].Numro <> Numro) et (i < 95) faire
i := i+1
fin tant que
si Trains[i].Numro = Numro
alors
Retourner (i)
sinon
Retourner (0)
fin si
fin
Notre nouvelle fonction comptant le nombre de TGV en retard sen trouve singulirement
raccourcie :
fonction NbrTVGRetard (TA : TableauArrives, Trains : tableau[95] de Train) : entier
var
i : entier
j : entier
Nbr : entier
dbut
Nbr := 0
pour i de 1 TA.NbrArrives
si TA.lment[i].Dcalage > 0
alors
j := RechercheTrain (Trains, TA.lment[i].Numro)
// je ne teste pas j>0 car ici je sais que le train existe
si Trains[j].Type = "TGV"
alors
Nbr := Nbr + 1
fin si
fin si
fin pour
Retourner (Nbr)
fin

52
8 3987 TC PA 00

Je me suis content de remplacer les instructions par lappel de la fonction. Nous pouvons optimiser ce code car ce nest pas lindice du train qui mintresse (la valeur de j) mais uniquement
si le train correspondant est un TGV. On peut donc remplacer la variable intermdiaire j par
sa valeur :
si TA.lment[i].Dcalage > 0
alors
si Trains[RechercheTrain (Trains, TA.lment[i].Numro)].Type = "TGV"
alors
Nbr := Nbr + 1
fin si
fin si
Ce nest pas fini : cette imbrication de si nest pas raisonnable :
si a
alors
si b
alors
Elle doit scrire :
si a et b
alors
Cela donne :
si (TA.lment[i].Dcalage > 0) et
(Trains[RechercheTrain (trains, TA.lment[i].Numro)].Type = "TGV")
alors
Nbr := Nbr + 1
fin si
Notre sous-programme final est donc :
fonction NbrTVGRetard (TA : TableauArrives, Trains : tableau[95] de Train) : entier
var
i : entier
j : entier
Nbr : entier
dbut
Nbr := 0
pour i de 1 TA.NbrArrives
si (TA.lment[i].Dcalage > 0) et
(Trains[RechercheTrain (trains, TA.lment[i].Numro)].Type = "TGV")
alors
Nbr := Nbr + 1
fin si
fin pour
Retourner (Nbr)
fin

53
8 3987 TC PA 00

Une petite prcision thorique. Jai dit ci-dessus que les deux si que javais imbriqus devaient
tre simplifis avec lemploi du connecteur logique et. Cest vrai sauf dans des cas trs particuliers. Voyez-vous lesquels ? Lorsque le boolen b nest pas valuable si a est faux. Ce nest
pas clair ? Voici un exemple :
si x <> 0
alors
si z/x < 100
alors
La smantique du si est formelle : la branche alors ne sera excute que si le test est vrai.
Appliquons cela : si x<>0 est vrai, on excute si z/x < 100 alors
Voyez-vous lintrt ? On ne calcule z/x que si x est diffrent de 0, ce qui est une bonne chose
car le programme planterait (division par 0) si x tait nul.
Si lon optimise limbrication de si, on obtient :
si (x <> 0) et (z/x < 100)
alors
Si x vaut 0, lvaluation du boolen plantera sur le calcul de z/x.
Soyons encore plus prcis : les compilateurs modernes proposent une valuation paresseuse
des boolens. Le principe est trs intuitif. Lapplication nvalue pas forcment lensemble
de lexpression boolenne car ds quelle en a assez calcul pour dterminer sa valeur, elle
sarrte. Cest simplement lexploitation des deux rgles suivantes (boolen est une expression boolenne quelconque) :
vrai ou boolen est vrai ;
faux et boolen est faux.
Par exemple :
x = 0 et y > 5. Si x vaut 3, on sait que le boolen est faux ds lvaluation de x = 0. Inutile
dvaluer y > 5.
x = y ou (z > 3 et t > 2 et lment[i].v[3].x = 2). Si x est gal y, inutile dvaluer lautre
terme du ou pour savoir que lexpression est vraie.
On parle dvaluation paresseuse car cest une expression rigolote et juste : on en fait le moins
possible. On pourrait tout aussi bien lappeler valuation intelligente car elle vite le travail
inutile.
Dans ce cas, x<>0 et z/x < 100 ne posera pas de problme car si x est nul, lvaluation du
boolen sarrte ds x<>0, sans faire de division par 0.
Attention, cela ne fonctionne que si le boolen est valu de gauche droite. Certains
compilateurs dcident eux-mmes de lordre dvaluation des termes des expressions boolennes. Dans ce cas, notre astuce ne fonctionne plus. Lorsque lon optimise ce point un
programme, il faut connatre parfaitement le fonctionnement de son compilateur.

54
8 3987 TC PA 00

Exercice 6
Je voulais vous faire crire au moins une fois un algorithme complet. Il fallait bien entendu
rutiliser la fonction de recherche prcdente.
algorithme Existence

// cette fonction est une copie de lexercice prcdent


fonction RechercheTrain (Trains : tableau[95] de Train, Numro : entier) : entier
var
i : entier
dbut
i := 1
tant que (Trains[i].Numro <> Numro) et (i < 95) faire
i := i+1
fin tant que
si Trains[i].Numro = Numro
alors
Retourner (i)
sinon
Retourner (0)
fin si
fin

// le sujet prcise que cette procdure est fournie


procdure InitTrains (var Trains : tableau[95] de Train)
dbut

fin
var
t : tableau[95] de Train
Num : entier
dbut
InitTrains (t)
saisir "Numro de train chercher ?", Num
si RechercheTrain (t, Num) = 0
alors
afficher "Ce train ne passe pas par la gare"
sinon
afficher "Ce train sarrte dans la gare"
fin si
fin
Aucune difcult si lon pense initialiser les variables, notamment le tableau des trains.

55
8 3987 TC PA 00

Exercice 7
Il faut rcuprer le numro du train de Limoges puis chercher ce train dans le tableau des
arrives. Pour rcuprer le numro, on adapte le sous-programme de recherche. Je vous rappelle que le sujet assure lexistence et lunicit du train venant de Limoges.
fonction RechercheTrainLimoges (Trains : tableau[95] de Train) : entier
var
i : entier
dbut
i := 1
tant que Trains[i].Provenance <> "Limoges"
i := i+1
fin tant que
Retourner (Trains[i].Numro)
fin
Le sujet assurant quil y a au moins une arrive, notre condition de boucle pour leur recherche est simplifie :
fonction NbrTrainsLimoges (TA : TableauArrives, Trains : tableau[95] de Train) : entier
var
i : entier
j : entier
NbrArrives : entier
dbut
j := RechercheTrainLimoges (Trains) // appel de la fonction ci-dessus
i := 1
tant que TA.lment[i].Numro < j faire
i := i+1
fin tant que
// Nous sommes sur la premire arrive du train de Limoges
NbrArrives := 0
rpter
NbrArrives := NbrArrives + 1
i := i+1
jusqu TA.lment[i].Numro > j
Retourner (NbrArrives)
fin

56
8 3987 TC PA 00

Assurez-vous de bien comprendre la boucle rpter ainsi que linitialisation de NbrArrives :


on lui affecte la valeur 0 alors que llment courant rpond pourtant la question. Est-ce
une erreur ? Non, car la boucle qui suit est un rpter dont le corps, excut au moins une
fois, incrmente NbrArrives.
Il est utile de passer par la variable intermdiaire j. Pourquoi ? Car en sen passant, on obtiendrait la boucle suivante :
tant que TA.lment[i].Numro < RechercheTrainLimoges (Trains) faire
Dans ce cas, le test tant valu chaque itration de la boucle, on appellera chaque fois
la fonction RechercheTrainLimoges. Cest coteux en temps de traitement. Il est donc plus
efficace de stocker la valeur dans une variable pour nappeler la fonction quune fois.
videmment, cette optimisation est importante lorsque lon crit un vrai programme. Au
niveau algorithmique (dans un devoir, lexamen) les deux critures sont tout aussi valables. Dune faon gnrale, loptimisation pousse nest pas utile en algorithmique. Vous ne
gagnerez pas de point avec, mais vous pouvez en perdre si votre optimisation est errone.
Conclusion ? Eh bien, pas de zle les zamis !

Exercice 8
Seule la fonction NbrTrainsLimoges change. Dans lexercice prcdent, on se positionnait sur
la premire arrive du train, puis on avanait dans le tableau jusquaux arrives dun autre
train.
La premire boucle doit maintenant vrier quune arrive existe bien. Cela donne :
fonction NbrTrainsLimoges (TA : TableauArrives, Trains : tableau[95] de Train) : entier
var
i : entier
j : entier
NbrArrives : entier
dbut
i := 1
j := RechercheTrainLimoges (Trains)
tant que (TA.lment[i].Numro < j) et (i < TA.NbrArrives)
i := i+1
fin tant que
NbrArrives := 0
// Fin de boucle car train trouv ou fin de tableau ?
si TA.lment[i].Numro = j
alors
rpter
NbrArrives := NbrArrives + 1
i := i+1
jusqu TA.lment[i].Numro > j
fin si
Retourner (NbrArrives)
fin

57
8 3987 TC PA 00

Exercice 9
Seule la fonction NbrTrainsLimoges change. Jutilise la dichotomie en vrifiant si lon trouve
bien une arrive. Ensuite, on travaille en deux temps : dans un premier, on recule pour trouver
les arrives prcdentes et dans un second, on avance pour trouver les arrives suivantes.
01 fonction NbrTrainsLimoges (TA : TableauArrives,
02
Trains : tableau[95] de Train) : entier
03 var
04
i : entier
05
j : entier
06
k : entier
07
NbrArrives : entier
08
Initial : entier
09
Final : entier
10
11 dbut
12
i := 1
13
j := RechercheTrainLimoges (Trains)
14
Initial := 1
15
Final := TA.NbrArrives
16
rpter
17
Milieu := (Initial+Final) div 2
18
si TA.lment[Milieu].Numro > j
19
alors
20
Final := Milieu-1
21
sinon
22
Initial := Milieu+1
23
fin si
24
jusqu (TA.lment[Milieu].Numro = j) ou (Dbut > Fin)
25
// pourquoi sommes-nous sortis ?
26
si TA.lment[Milieu].Numro = j
27
alors
28
NbrArrives := 1 // Nous sommes sur une arrive de notre train
29
// Y en a-t-il avant ? Je recule jusqu changer de train ou
30
//
tre au dbut du tableau
31
k := Milieu 1
32
tant que (TA.lment[k].Numro = j) et (k > 1) faire
33
NbrArrives := NbrArrives+1
34
k := k-1
35
fin tant que
36
// pourquoi suis-je sorti de la boucle ?
37
si TA.lment[k].Numro = j
38
alors

58
8 3987 TC PA 00

39
// je suis sorti car arriv au premier lment et celui-ci contient
40
mon train. Je le comptabilise
41
NbrArrives := NbrArrives+1
42
fin si
43
// Y en a-t-il aprs ? Javance jusqu changer de train ou
44
//
tre en fin de tableau
45
k := Milieu + 1
46
tant que (TA.lment[k].Numro = j) et (k < TA.NbrArrives) faire
47
NbrArrives := NbrArrives+1
48
k := k+1
49
fin tant que
50
// pourquoi suis-je sorti de la boucle ?
51
si TA.lment[k].Numro = j
52
alors
53
// je suis sorti car arriv au dernier lment et celui-ci contient
54
mon train. Je le comptabilise
55
NbrArrives := NbrArrives+1
56
fin si
57
Retourner (NbrArrives)
58
sinon
59
Retourner (0)
60
fin si
61 fin
Vrifiez que vous comprenez bien la recherche en arrire puis en avant et notamment lutilisation du tant que. Comme je nexploite pas la notion dvaluation paresseuse des boolens
(voir corrig de lexercice 5), la prise en compte des bornes du tableau est trs lourde :
lignes 36 42, je dois vrifier si la premire arrive concerne mon train. En effet, je nai
pas pu le faire dans la boucle cause de la condition k > 1 (ligne 32) ;
lignes 50 56, je dois vrifier si la dernire arrive concerne mon train. En effet, je nai pas
pu le faire dans la boucle cause de la condition k < TA.NbrArrives (ligne 46).
Dans les deux boucles tant que, nous avons besoin dune nouvelle variable locale k pour les
parcours en arrire et en avant car si lon dcrmentait directement Milieu, on ne saurait plus
do repartir une fois quil faudrait chercher vers lavant.
Enfin, en rflchissant un peu, on peut le savoir. Nous allons voir cela.
Lorsque lon est sur llment dindice Milieu, NbrArrives est initialis 1 (llment Milieu
fait partie de ceux que lon cherche). Ensuite, on recule en incrmentant NbrArrives jusqu ce que lon ne soit plus sur une arrive du train que lon cherche. Comme NbrArrives
a volu paralllement notre parcours, on peut donc trouver une formule dpendant de
NbrArrives permettant de retrouver la valeur initiale de Milieu. Nous pouvons donc nous
passer de k et travailler directement avec Milieu.

59
8 3987 TC PA 00

Pour trouver la formule, prenons un exemple :


1

Milieu vaut 5 (on cherche les valeurs 4) et NbrArrives vaut 1.


On va reculer (Milieu vaudra successivement 4 puis 3) et NbrArrives passera 2 puis 3.
tape suivante : on recule encore (Milieu vaut 2) mais nous ne sommes plus sur la valeur
que nous cherchions donc NbrArrives reste 3. La valeur initiale de Milieu (soit 5) est
NbrArrives+Milieu.
Je peux maintenant rcrire le traitement concern sans utiliser la variable k (en gras les
modifications) :
// Nous sommes sur une arrive de notre train
NbrArrives := 1
// Y en a-t-il avant ?
Milieu := Milieu 1
tant (que TA.lment[Milieu].Numro = j) et(k > 1) faire
NbrArrives := NbrArrives+1
Milieu := Milieu-1
fin tant que
// pourquoi suis-je sorti de la boucle ?
si TA.lment[k].Numro = j
alors
// je suis sorti car arriv au premier lment et celui-ci contient
// mon train. Je le comptabilise
NbrArrives := NbrArrives+1
fin si
// Y en a-t-il aprs ?
Milieu := Milieu + NbrArrives + 1
tant que (TA.lment[Milieu].Numro = j) et (k < TA.NbrArrives) faire
NbrArrives := NbrArrives+1
Milieu := Milieu+1
fin tant que
// pourquoi suis-je sorti de la boucle ?
si TA.lment[k].Numro = j
alors
// je suis sorti car arriv au dernier lment et celui-ci contient
// mon train. Je le comptabilise
NbrArrives := NbrArrives+1
fin si
Quelle solution employer ? La seconde est lgante, optimise, on conomise une variable
cest super !
Et bien non. Le gain de temps engendr (on conomise la cration puis la destruction dune
variable locale) est absolument imperceptible. En contrepartie, nous avons un algorithme

60
8 3987 TC PA 00

beaucoup moins vident comprendre. Il nous a fallu passer par un exemple pour tablir
la formule permettant de retrouver llment dindice Milieu du dpart. Cette formule, peu
intuitive, est source derreur.
En conclusion, loptimisation apporte autant defcacit que de complexit. Il ne faut pas
jouer au programmeur fou : la simplicit du code, qui limite les bugs et aide la maintenance
ultrieure, est aussi importante que lefcacit.
Il faut donc savoir ne pas en faire trop.
Ici, il ny a aucune hsitation avoir : on retient le premier algorithme car loptimisation est
bien plus complexe quefcace.

Exercice 10
Il nest plus possible dcrire une fonction renvoyant les trains dune ville donne car
chaque appel, elle ne pourrait renvoyer que le premier train trouv. Pour empcher cela, il
faudrait passer lindice du prcdent train trouv pour que la recherche commence au-del.
De plus, la recherche dun train donn produit un seul rsultat, tandis que ce que nous voulons, cest un rsultat indtermin (0 n trains). Cest donc plus logiquement une boucle
lintrieur du sous-programme que nous crirons.
Finalement, cest le sous-programme de parcours du tableau des trains qui appellera un sousprogramme de calcul du nombre darrives de ce train.
Le principe sera le suivant : on va parcourir le tableau des trains. Pour chaque train venant de la
ville souhaite, on va rechercher dans le tableau des arrives son nombre darrives. On peut alors
raliser notre petit calcul donnant statistiquement le nombre de passagers arrivs par ce train.
algorithme exo_10
// cette fonction renvoie le nombre darrives dun train donn
// cest la fonction NbrTrainsLimoges de lexercice prcdent o j est
// remplac par le paramtre Numro
fonction NbrTrains (TA : TableauArrives, Numro : entier) : entier
var
i : entier
k : entier
NbrArrives : entier
Milieu : entier
Initial : entier
Final : entier
dbut
i := 1
Initial := 1
Final := TA.NbrArrives
rpter
Milieu := (Initial+Final) div 2

61
8 3987 TC PA 00

si TA.lment[Milieu].Numro > Numro


alors
Final := Milieu-1
sinon
Initial := Milieu+1
fin si
jusqu TA.lment[Milieu].Numro = Numro ou Initial > Final
// pourquoi sommes-nous sortis ?
si TA.lment[Milieu].Numro = Numro
alors
NbrArrives := 1 // Nous sommes sur une arrive de notre train
// Y en a-t-il avant ? Je recule jusqu changer de train ou
//
tre au dbut du tableau
k := Milieu 1
tant que (TA.lment[k].Numro = j) et(k > 1) faire
NbrArrives := NbrArrives+1
k := k-1
fin tant que
// pourquoi suis-je sorti de la boucle ?
si TA.lment[k].Numro = j
alors
// je suis sorti car arriv au premier lment et celui-ci contient
mon train. Je le comptabilise
NbrArrives := NbrArrives+1
fin si
// Y en a-t-il aprs ? Javance jusqu changer de train ou
//
tre en fin de tableau
k := Milieu + 1
tant que (TA.lment[k].Numro = j) et (k < TA.NbrArrives) faire
NbrArrives := NbrArrives+1
k := k+1
fin tant que
// pourquoi suis-je sorti de la boucle ?
si TA.lment[k].Numro = j
alors
// je suis sorti car arriv au dernier lment et celui-ci contient
mon train. Je le comptabilise
NbrArrives := NbrArrives+1
fin si
Retourner (NbrArrives)
sinon

62
8 3987 TC PA 00

Retourner (0)
fin si
fin

fonction NbrPassagers (TA : TableauArrives, Trains : tableau[95] de Train, Ville : string) : rel
var
i : entier
NbrPass : rel // car calcul statistique
dbut
NbrPass := 0
pour i de 1 95
si Trains[i].Provenance = Ville
alors
NbrPass := NbrPass +
(Trains[i].NbrPlaces1*0.65+Trains[i].NbrPlaces2*0.79)*
NbrTrains (TA, Trains[i].Numro)
fin si
fin pour
Retourner (NbrPass)
fin

// le sujet prcise que cette fonction est fournie


procdure InitTrains (var Trains : tableau[95] de Train)
dbut

fin

// le sujet prcise que cette fonction est fournie


procdure InitArrives (var TA : TableauArrives)
dbut

fin

63
8 3987 TC PA 00

var
TabTrains : Tableau[95] de Train
TabArrives : TableauArrives
VilleOrigine : chane
dbut
InitTrains (TabTrains)
InitArrives (TabArrives)
saisir "Ville dorigine ?", VilleOrigine
afficher "Nombre estim de passagers arrivs :", NbrPassagers (TabArrives, TabTrains, VilleOrigine)
fin
Quelques explications sont ncessaires :
jai ajout une procdure InitArrives que je suppose fournie (voir le sujet) pour remplir
le tableau des arrives. Cette initialisation est sans doute ralise par lintermdiaire
dun fichier ou dune base de donnes. Cela ne nous concerne pas ici ;
la fonction NbrPassagers prend en paramtre le tableau des arrives. Elle ne sen sert pas
directement, mais le passe en paramtre la fonction NbrTrains qui elle, en a besoin.
Elle renvoie un nombre rel pour plus de prcision ;
pour calculer le nombre de passagers pour toutes les arrives dun train donn, je multiplie le nombre moyen de passagers pour une arrive par le nombre darrives ;
si aucun train nest en provenance de la ville demande, tout se passe bien (le rsultat
est 0) ;
sil existe des trains de cette ville mais quaucun nest arriv dans la gare (il est donc
prsent dans le tableau des trains mais pas dans celui des arrives), on aura une multiplication par 0, donc un rsultat correct de 0.
La leon retenir ? Ma foi, face un exercice complexe, pas de panique : dcomposez le travail
en sous-programmes et identifiez les boucles et tests ncessaires. Le plus dur est alors fait.
Ensuite, il faut de la rigueur et surtout se relire. (La premire version de ma correction avait
un bug. Pour tre honnte, la deuxime aussi.)

64
8 3987 TC PA 00

Travaux dirigs 3

Dsol, mais l, je ne vois pas trop quel corrig je pourrais bien vous fournir
Ce TD a pour objet de vous faire manipuler votre langage de programmation
favori.
Plus vous y passerez de temps entre la fin de ltude du cours et lexamen et
mieux vous serez prpar.
Bon courage pour lutilisation du langage (srieux, faites-le !).

65
8 3987 TC PA 00

Corrig du devoir autocorrectif

Exercice 1
1. Moyenne pour une matire donne
Nous allons chercher le numro de la matire (et non son indice) dun libell donn avec la
fonction suivante :
fonction RenvoieNumroMatire (Tm : TabMatires, Libell : chane) : entier var
i : integer
dbut
i := 1
tant que Tm.t[i].Libell <> Libell faire
i := i+1
fin tant que
Rsultat := Tm.t[i].Num
fin
Notez que cette fonction de recherche est minimaliste car le sujet indique que la matire existe forcment. On aura donc toujours trouv ce que lon cherche avant de sortir du tableau.
Pour trouver les notes de cette matire, on bnficie du fait que le tableau est tri par matire. Je vais donc avancer dans ce tableau jusqu arriver sur les notes de la matire cherche
puis je traite les notes successives jusqu changer de matire.
Voici le code :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22

fonction MoyenneMatire (Tm : TabMatires, Libell : chane, Tn : TabNotes) : rel


var
i : integer
NumMatire : entier
Somme : entier
NbrNotes : entier
dbut
NumMatire := RenvoieNumroMatire (Tm, Libell)
i := 1
tant que Tn.t[i].NumMatire <> NumMatire faire
i := i+1
fin tant que
NbrNotes := 0
Somme := 0
tant que Tn.t[i].NumMatire = NumMatire faire
NbrNotes := NbrNotes + 1
Somme := Somme + Tn.t[i].Note
i := i+1
fin tant que
Rsultat := Somme/NbrNotes
fin

67
8 3987 TC PA 00

Vrifions que ce programme fait bien ce qui tait attendu :


ligne 9, on rcupre le numro de la matire dont on veut la moyenne ;
lignes 11 13, on avance dans le tableau des notes jusqu atteindre celles de la matire
cherche ;
lignes 16 20, on prend en compte chaque note jusqu changer de matire ;
ligne 22, on fait le calcul.
2. Moyenne pour un tudiant donn
Cest le mme type de traitement que la question prcdente. Comme vous vous doutez
bien que je ne vous demande pas deux fois le mme algorithme, nous allons numrer les
diffrences :
ltudiant cherch peut ne pas exister. Il faudra donc crire une fonction RenvoieNumro
prenant cela en compte ;
le tableau de notes tant tri par matires, cest comme sil ntait pas tri lorsque lon
cherche toutes les notes dun tudiant donn donc quon le parcourt par tudiant.
Nous allons chercher le numro de ltudiant dun nom donn avec la fonction suivante :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15

fonction RenvoieNumrotudiant (C : Classe, Nom : chane, Prnom : chane) : entier


var
i : integer
dbut
i := 1
tant que i < C.Nbrtudiants et C.t[i].Nom <> Nom et
C.t[i].Prnom <> Prnom faire
i := i+1
fin tant que
si (C.t[i].Nom = Nom) et (C.t[i].Prnom = Prnom)
alors
Rsultat := C.t[i].Num
sinon
Rsultat := -1
fin

Notez que dans ma boucle, je vrifie que mon indice i est valide (ligne 6), puis, ligne 10, je
vrifie si la sortie de boucle correspond une recherche fructueuse ou non. Si je nai pas
trouv ltudiant, je renvoie 1 qui nest pas un numro valide.
Pour calculer la moyenne de ltudiant, jai besoin de connatre le coefficient des matires,
do cette fonction :
fonction RenvoieCoefficient (Tm : TabMatires, Num : entier) : entier var
i : integer
dbut
i := 1
tant que Tm.t[i].Num <> Num faire
i := i+1
fin tant que
Rsultat := Tm.t[i].Coefficient
fin

68
8 3987 TC PA 00

Elle ressemble trs fortement RenvoieNumroMatire de la premire question car je suis


certain de trouver la matire.
Calcul de la moyenne :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

fonction Moyennetudiant (C : Classe, Nom : chane, Prnom : chane,


Tn : TabNotes Tm : TabMatieres) : rel
var
i : integer
Numtudiant : entier
Somme : entier
Coeff : entier
SommeCoeffs : entier
dbut
Numtudiant := RenvoieNumrotudiant (C, Nom, Prnom)
si Numtudiant = -1
alors
Rsultat := -1
sinon
Somme := 0
SommeCoeffs := 0
pour i de 1 Tn.NbrNotes
si Tn.t[i].Numtudiant = Numtudiant
alors
Coeff := RenvoieCoefficient (Tm, Tn.t[i].NumMatire)
Somme := Somme + Tn.t[i].Note * Coeff
SommeCoeffs := SommeCoeffs + Coeff
fin si
fin pour
Rsultat := Somme/SommeCoeffs
fin si
fin

Doit-on expliquer ? Un peu :


ligne 11, je rcupre le numro de ltudiant cherch ;
lignes 12 et 14, si cet tudiant nexiste pas, je renvoie 1 qui nest pas une moyenne
valide. Le programme appelant saura donc que ltudiant nest pas dans le tableau ;
ligne 18, comme le tableau des notes nest pas tri par tudiant, je dois le parcourir du
dbut la fin donc une boucle pour simpose ;
lignes 19 25, si la note courante est attribue ltudiant qui mintresse (ligne 19), je
vais chercher le coefficient de la matire correspondante (ligne 21) et je fais mes petits
calculs, cumul de la note (ligne 22) et du coefficient (ligne 23).

69
8 3987 TC PA 00

Exercice 2
Le principe de lalgorithme est simple : je vais parcourir le tableau des tranches horaires. Pour
chacune, je vais parcourir le tableau des appels pour rcuprer les appels correspondants. Je
ferai alors mon petit calcul.
La structure des variables utilises est identique celle de lexercice prcdent. Le traitement
sera en revanche un peu diffrent. En effet, dans lexercice prcdent, nous voulions les
notes concernant un tudiant ou une matire donne, tandis quici nous voulons accder
successivement aux appels de toutes les tranches horaires.
Nous allons donc parcourir les deux tableaux conjointement.
Le principe sera le suivant :
jai deux variables IndiceTt (Tt pour TabTarifs) et IndiceTa (Ta pour TabAppels) matrialisant lindice courant dans les tableaux TabTarifs et TabAppels ;
pour chaque tranche horaire (soit pour chaque valeur de IndiceTt), javance IndiceTa
pour accder tous les appels correspondants. Lorsque IndiceTa correspond un appel
dune autre tranche horaire, jarrte davancer dans TabAppels et je recommence (soit
javance IndiceTt pour passer la tranche horaire suivante).
Cet algorithme est efficace car je ne parcours chaque tableau quune fois. Il fonctionne grce
au fait que le tableau des appels est tri par tranche horaire (cest dit dans le sujet).
Dtaillons le calcul de la tarification de chaque appel. Pour cela, prenons notre algorithme
en cours de route.
Je suis sur la tranche horaire IndiceTt. Chaque appel :
me donne droit TabTarifs[IndiceTt].NbrSecGratuites secondes gratuites ;
me cote, au-del de la dure gratuite, TabTarifs[IndiceTt].TarifSeconde euros par seconde.
Je suis sur lappel IndiceTa. Celui-ci :
a t pass dans la tranche horaire TabAppels.t[IndiceTa].TrancheHoraire (qui doit tre
gal IndiceTt si mon algorithme est correct) ;
a dur TabAppels.t[IndiceTa]. Dure secondes.
Combien ma cot cet appel ? Eh bien :
les frais fixes de 0,046 ;
le prix de la seconde (TabTarifs[IndiceTt].TarifSeconde) multipli par le nombre de
secondes payantes, soit la dure de lappel moins les secondes gratuites (TabAppels.
t[IndiceTa].Dure -TabTarifs[IndiceTt].NbrSecGratuites).
Attention au pige : si mon appel a dur moins de temps que les secondes gratuites, le nombre Dure-NbrSecGratuites sera ngatif, ce qui entranerait le remboursement des secondes
gratuites non consommes. Comme ce nest pas le cas, je dois arrondir ce nombre 0 ;
cela indique que je ne paye rien au titre de la dure. Cette petite subtilit me donne loccasion dcrire la fonction ZroSiNgatif ci-dessous.
fonction ZroSiNgatif (var e : entier) : entier
dbut
si e < 0
alors
Rsultat := 0
sinon
Rsultat := e
fin si
fin

70
8 3987 TC PA 00

Voici lalgorithme (pour raccourcir les critures, TabTarifs devient Tt, IndiceTt dvient IndTt et
idem pour ce qui concerne le tableau des appels).
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20

fonction Tarif (Tt : tableau [24] de Tarif, Ta : TypeTabAppels) : rel


var
IndTa : entier
IndTt : entier
Somme : rel
dbut
IndTa := 1
Somme := 0
pour IndTt de 1 24
tant que (IndTa <= Ta.NbrAppels) et
(Ta.t[IndTa].TrancheHoraire = IndTt) faire
Somme := Somme + 0,046 +
Tt[IndTt].TarifSeconde *
ZroSiNgatif (Ta.t[IndTa].Dure - Tt[IndTt].NbrSecGratuites)
IndTa := IndTa + 1
fin tant que
fin pour
Rsultat := Somme
fin

Quelques explications :
comme je vais de la premire la dernire tranche horaire, je fais une boucle pour (ligne 10) ;
ligne 11, je vrifie que IndTa est valide, soit que la valeur nest pas suprieure au nombre
dappels contenus dans le tableau ;
ligne 12, on vrifie que llment courant du tableau des appels correspond la bonne
tranche horaire ;
lignes 13 15, on effectue le calcul.

71
8 3987 TC PA 00