Algorithmique et langages
Autocorrection
Sommaire
Squence 1 : Variables et instructrions
15
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
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
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
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
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
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
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
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
Exercice 21
Le corrig est dans la suite du cours.
18
8 3987 TC PA 00
Squence 3
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
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
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
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.
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
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
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
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 :
(i-1) + 18
28
8 3987 TC PA 00
Au final :
18
23
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
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
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
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
35
8 3987 TC PA 00
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
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
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
43
8 3987 TC PA 00
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
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
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
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
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
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
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
fin
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
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
67
8 3987 TC PA 00
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
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
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