-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy path2012Logique2eme.tex
5779 lines (4661 loc) · 171 KB
/
2012Logique2eme.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\begin{flushleft}
\tablefirsthead{}
\tablehead{}
\tabletail{}
\tablelasttail{}
\begin{supertabular}{m{11.242001cm}m{4.741cm}}
{\sffamily\bfseries Chapitre 2~-- La pile}
~
&
\raggedleft\arraybslash \includegraphics[width=2.009cm,height=3.847cm]{a2012Logique2eme-img011.png} \\
\end{supertabular}
\end{flushleft}
\bigskip
\section[Définition]{\sffamily Définition}
{
Une \textbf{p}\textbf{ile} est une collection d'éléments admettant les fonctionnalités suivantes :}
\liststyleWWviiiNumxxv
\begin{itemize}
\item {
on peut toujours ajouter un élément à la collection}
\item {
seul le dernier élément ajouté peut être consulté ou enlevé}
\item {
on peut savoir si la collection est vide}
\end{itemize}
\bigskip
{
La pile (en anglais \textit{stack}) est donc une collection de données de type \textit{dernier entré, premier sorti} (en
anglais on dit ``LIFO'', c'est-à-dire \textit{last in first out}). L'analogie avec la pile de dossiers sur un bureau
est claire : les dossiers sont déposés et retirés du sommet \textstyleEmphasis{\textup{et on ne peut jamais ajouter,
retirer ou consulter un dossier qui se trouve ailleurs dans la pile}}.}
{\centering \includegraphics[width=7.553cm,height=4.357cm]{a2012Logique2eme-img012.jpg} \par}
{
On ne peut donc pas parcourir une pile, ou consulter directement le \textit{n}{}-ème élément. Les opérations permises
avec les piles sont donc peu nombreuses, mais c'est précisément là leur spécificité : elles ne sont utilisées en
informatique que dans des situations particulières où seules ces opérations sont requises et utilisées. Paradoxalement,
on implémentera une pile en restreignant des structures plus riches aux seules opérations autorisées par les piles.}
{
Des exemples d'utilisations sont la gestion de la mémoire par les micro-processeurs, l'évaluation des expressions
mathématiques en notation polonaise inverse, la fonction «~ctrl-Z~» dans un traitement de texte qui permet d'annuler
les frappes précédentes, la mémorisation des pages web visitées par un navigateur, etc. Nous les utiliserons aussi plus
loin dans ce cours pour parcourir les arbres et les graphes.}
\section[Implémentation orienté{}-objet]{\sffamily Implémentation orienté-objet}
{
Nous allons d'abord décrire l'allure générale de la classe pile. Nous ne précisons pas encore les détails de
l'implémentation, plusieurs possibilités existent, que nous détaillerons à titre d'exercice.}
\bigskip
\bigskip
{\sffamily
\textbf{classe} Pile<T>\ \ \ \ \ \ \ \ \ \ // T est le type des éléments de la pile}
{\sffamily
\textbf{\ \ \ \ \ }\textbf{privé} :\ \ \ \ \ \ \ \ \ \ \ \ // à détailler plus tard}
{\sffamily
\textbf{\ \ \ \ \ }\textbf{public} :}
{\sffamily
\textbf{\ \ \ \ \ \ \ \ \ \ }\textbf{constructeur} Pile<T>( ) \ \ \ \ \ \ // crée une pile vide}
{\sffamily
\textbf{\ \ \ \ \ \ \ \ \ \ }\textbf{méthode} empiler(élément : T)\ \ \ \ // ajoute un élément au sommet de la pile}
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ sommet( ) }$\rightarrow $
\textsf{T\ \ \ \ \ \ // retourne la valeur de l'élément au sommet}}
{\sffamily
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ // de la pile, sans le retirer}
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ dépiler( ) }$\rightarrow $\textsf{
T\ \ \ \ \ \ // enlève et retourne l'élément au sommet}}
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ estVide( ) }$\rightarrow $\textsf{
booléen\ \ \ \ // indique si la pile est vile\ \ }}
{\sffamily\bfseries
fin classe}
\subsection[Remarques~:]{ Remarques :}
\liststyleWWviiiNumxxiii
\begin{itemize}
\item {
Théoriquement, et dans la majorité des utilisations, la pile est \textit{infinie}, c'est-à-dire qu'on peut y ajouter un
nombre indéterminé d'éléments (comme c'était le cas pour la classe Liste étudiée en 1\textsuperscript{ère} année). Dans
certaines situations, on peut cependant imposer une capacité maximale à la pile (en pratique, c'est le cas de la pile
de dossiers dans un bureau, elle est forcément limitée par la hauteur du plafond !). Nous aborderons ce cas particulier
dans les exercices. }
\item {
Lors de l'implémentation de la classe, il faudra songer à envoyer un message d'erreur lorsqu'on utilise les méthodes
\textit{sommet} et \textit{dépiler} si la pile est vide. Si la pile possède une taille maximale, alors c'est
\textit{empiler} qui doit générer un message d'erreur lorsque la pile est pleine.}
\item {
Nous avons utilisé ici des noms de méthodes neutres indépendants de tout langage de programmation. Dans la littérature
anglaise, on trouvera souvent \textit{push}, \textit{top} et \textit{pop} en lieu et place de \textit{empiler},
\textit{sommet} et \textit{dépiler}.}
\end{itemize}
\section[Exemple d{}'utilisation]{\sffamily Exemple d'utilisation}
{\color{black}
Afin d'illustrer l'utilisation de la classe Pile, nous donnons pour exemple un algorithme qui lit une suite
d'enregistrements d'un fichier \textbf{fileIn} (de type \textbf{Info}) et les reproduit en ordre inverse dans le
fichier \textbf{fileOut}.}
{\sffamily
\textbf{module} inverserOrdre(fileIn$\downarrow $: FichierEntrée d'Info, fileOut$\uparrow $ : FichierSortie d'Info)}
{\sffamily
\ \ enr : Info}
{\sffamily
\ \ \ \ \ pile : Pile<Info>}
\bigskip
{\sffamily
\ \ \ \ \ // 1\textsuperscript{ère} étape : parcours du fichier et mise en pile}
{\sffamily
\ \ \ \ \ pile $\leftarrow $ \textbf{nouvelle} Pile<Info>}
{\sffamily
\ \ \ \ \ fileIn.ouvrir( )}
{\sffamily
\ \ \ \ \ enr $\leftarrow $ fileIn.lire( )}
{\sffamily
\textbf{\ \ \ \ \ }\textbf{tant que} NON fileIn.EOF( ) \textbf{faire}}
{\sffamily
\ \ \ \ \ \ \ \ \ \ pile.empiler(enr)}
{\sffamily
\ \ \ \ \ \ \ \ \ \ enr $\leftarrow $ fileIn.lire( )}
{\sffamily\bfseries
\ \ \ \ \ fin tant que}
{\sffamily
\ \ \ \ \ fileIn.fermer( )}
{\sffamily
\ \ \ \ \ // 2\textsuperscript{ème} étape : vider la pile et écrire les éléments dans le fichier de sortie}
{\sffamily
\ \ \ \ \ fileOut.ouvrir( )}
{\sffamily
\textbf{\ \ \ \ \ }\textbf{tant que} NON pile.estVide( ) \textbf{faire}}
{\sffamily
\ \ \ \ \ \ \ \ \ \ enr $\leftarrow $ pile.dépiler( )}
{\sffamily
\ \ \ \ \ \ \ \ \ \ fileOut.écrire(enr)}
{\sffamily\bfseries
\ \ \ \ \ fin tant que}
{\sffamily
\ \ \ \ \ fileOut.fermer( )}
{\sffamily\bfseries
fin module}
\section[Exercices]{\sffamily Exercices}
\section[Ex. 1. Implémentation via une~liste chainée]{\sffamily Ex. 1. Implémentation via
une~liste chainée}
{\color{black}
Détaillez l'implémentation de la classe pile en utilisant comme attribut privé une liste chainée. Veillez à utiliser les
méthodes qui permettent la gestion la plus efficace.}
\section[Ex. 2. La pile de taille finie]{\sffamily Ex. 2. La pile de taille finie}
{
On envisage ici une pile dont la capacité est limitée : elle ne peut contenir au plus qu'un nombre donné d'éléments. On
demande d'implémenter ce type de pile en utilisant un tableau. Les attributs privés de la classe seront~les suivants :}
\bigskip
{\sffamily
\textbf{privé~}:}
{\sffamily
\ \ \ \ \ tab : \textbf{tableau} de T \ \ \ \ // tableau (dynamique) contenant les éléments de la pile}
{\sffamily
\ \ \ \ \ indSommet : entier\textbf{\textit{ \ \ \ \ }}// indice du sommet de la pile}
{\sffamily
\ \ \ \ \ tailleMax : entier\textbf{\textit{ \ \ \ \ }}// taille maximale de la pile}
{
On remplira le tableau en ajoutant les éléments les uns à la suite des autres et en retenant la position du dernier
élément, qui correspondra à la valeur de l'attribut \textbf{sommet}. Cet attribut augmentera lorsqu'on ajoute un
élément, et va décroître lorsqu'on en retire un.}
\section[Détaillez l{}'implémentation des méthodes de la classe pile correspondant à cette situation. Il faudra aussi
adapter le constructeur, en lui donnant comme paramètre la taille maximale de la pile.]{
Détaillez l'implémentation des méthodes de la classe pile correspondant à cette situation. Il faudra aussi adapter le
constructeur, en lui donnant comme paramètre la taille maximale de la pile.}
\section[Ex. 3. L{}'itinéraire retour]{\sffamily Ex. 3. L'itinéraire retour}
{\color{black}
Un fichier \textbf{aller} contient la description d'un itinéraire. Chaque enregistrement du fichier est une structure
\textbf{étape} contenant les champs \textbf{ville} (chaine) et \textbf{km} (réel). Ecrire un algorithme qui crée le
fichier \textbf{retour} qui contiendra -- au même format que \textbf{aller} -- la description de l'itinéraire retour.}
{\itshape\color{black}
Exemple.}
{
\textbf{aller}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \textbf{retour}}
{
Bruxelles\ \ \ \ 0\ \ \ \ \ \ \ \ Amsterdam\ \ \ \ 0}
{
Antwerpen\ \ \ \ 40\ \ \ \ \ \ \ \ Utrecht\ \ \ \ 50}
{
Breda\ \ \ \ \ \ 100\ \ \ \ \ \ \ \ Breda\ \ \ \ \ \ 120}
{
Utrecht\ \ \ \ 170\ \ \ \ \ \ \ \ Antwerpen\ \ \ \ 180}
{
Amsterdam\ \ \ \ 220\ \ \ \ \ \ \ \ Bruxelles\ \ \ \ 220}
\bigskip
\bigskip
\bigskip
\bigskip
\bigskip
\bigskip
\begin{flushleft}
\tablefirsthead{}
\tablehead{}
\tabletail{}
\tablelasttail{}
\begin{supertabular}{m{11.032001cm}m{4.951cm}}
{\sffamily\bfseries Chapitre 3~-- La file}
~
&
\includegraphics[width=4.77cm,height=3.567cm]{a2012Logique2eme-img013.jpg} \\
\end{supertabular}
\end{flushleft}
\bigskip
\section[Définition]{\sffamily Définition}
{
Une \textbf{f}\textbf{ile} est une collection d'éléments admettant les fonctionnalités suivantes :}
\liststyleWWviiiNumxxv
\begin{itemize}
\item {
on peut toujours ajouter un élément à la collection}
\item {
seul le premier élément ajouté peut être consulté ou enlevé}
\item {
on peut savoir si la collection est vide}
\end{itemize}
\bigskip
{
La file (en anglais \textit{queue}) est donc une collection de données de type \textit{premier}\textit{ entré, premier
sorti} (en anglais on dit ``FIFO'', c'est-à-dire \textit{first in first out}). L'analogie avec une file de clients à un
guichet (poste, caisse du supermarché{\dots}) est évidente : c'est le premier arrivé qui est le premier servi, et il
est très malvenu d'essayer de doubler une personne dans une file ! Noter qu'une fois entré dans une \textit{file} -- au
sens informatique du terme -- on ne peut pas en sortir par l'arrière, le seul scénario possible pour en sortir est
d'attendre patiemment son tour et d'arriver en tête de la file.}
{
De même que pour la pile, on ne peut donc non plus parcourir une file, ou consulter directement le \textit{n}{}-ème
élément. Les files sont très utiles en informatique, citons par exemple la création de mémoire tampon (\textit{buffer})
dans de nombreuses applications, les processeurs multitâches qui doivent accorder du temps-machine à chaque tâche, la
file d'attente des impressions pour une imprimante{\dots}}
\section[Implémentation orienté{}-objet]{\sffamily Implémentation orienté-objet}
{
Comme pour la pile, la classe File ne contient qu'un nombre restreint de méthodes qui correspondent aux quelques
opérations permises avec cette structure : ajouter un élément (\textit{«~enfiler~»}), consulter l'élément de tête, et
le retirer (\textit{«~enfiler~»}). Comme précédemment, nous ne décrivons que les entêtes des constructeur et méthodes,
le détail de l'implémentation sera laissé à titre d'exercices.}
\bigskip
{\sffamily
\textbf{classe} File<T>\ \ \ \ \ \ \ \ \ \ // T est le type des éléments de la file}
{\sffamily
\textbf{\ \ \ \ \ }\textbf{privé} :\ \ \ \ \ \ \ \ \ \ \ \ // à détailler plus tard}
{\sffamily
\textbf{\ \ \ \ \ }\textbf{public} :}
{\sffamily
\textbf{\ \ \ \ \ \ \ \ \ \ }\textbf{constructeur} File<T>( ) \ \ \ \ \ \ // crée une file vide}
{\sffamily
\textbf{\ \ \ \ \ \ \ \ \ \ }\textbf{méthode} enfiler(élément : T)\ \ \ \ // ajoute un élément dans la file}
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ tête( ) }$\rightarrow $ \textsf{T\ \ \ \ \ \ //
retourne la valeur de l'élément en tête}}
{\sffamily
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ // de file, sans le retirer}
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ défiler( ) }$\rightarrow $\textsf{
T\ \ \ \ \ \ // enlève et retourne l'élément de tête}}
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ estVide( ) }$\rightarrow $\textsf{
booléen\ \ \ \ // indique si la file est vile\ \ }}
{\sffamily\bfseries
fin classe}
\subsection[]{ }
\subsection[Remarques~:]{ Remarques :}
\liststyleWWviiiNumxxiii
\begin{itemize}
\item {
De même que dans le chapitre précédent, la file est supposée \textit{infinie}, c'est-à-dire qu'on peut y ajouter un
nombre indéterminé d'éléments. Le cas de la file limitée à une capacité maximale sera envisagé dans l'exercice 2. }
\item {
Dans l'implémentation, il faudra songer à envoyer un message d'erreur lorsqu'on utilise les méthodes \textit{tête} et
\textit{défiler} si la file est vide. Si la file possède une taille maximale, alors c'est \textit{enfiler} qui doit
générer un message d'erreur lorsque la file est pleine.}
\end{itemize}
\section[Exercices]{\sffamily Exercices}
\section[Ex. 1. Implémentation via une~liste chainée~bidirectionnelle]{\sffamily Ex. 1.
Implémentation via une~liste chainée~bidirectionnelle}
{\color{black}
Détaillez l'implémentation de la classe file en utilisant comme représentation des données une liste chainée
bidirectionnelle.}
\section[Ex. 2. La file de taille limitée]{\sffamily Ex. 2. La file de taille limitée}
{
La file de taille limitée ne peut contenir au plus qu'un nombre donné d'éléments. On demande d'implémenter ce type de
file en utilisant un tableau. Les attributs privés de la classe seront~les suivants :}
\bigskip
{\sffamily
\textbf{privé~}:}
{\sffamily
\ \ \ \ \ tab : \textbf{tableau} de T \ \ \ \ // tableau (dynamique) contenant les éléments de la file}
{\sffamily
\ \ \ \ \ premier : entier\textbf{\textit{ \ \ \ \ }}// indice du premier élément entré (tête de file)}
{\sffamily
\ \ \ \ \ dernier : entier\textbf{\textit{ \ \ \ \ }}// indice du dernier élément entré (fin de file)}
{\sffamily
\ \ \ \ \ tailleMax : entier\textbf{\textit{ \ \ \ \ }}// taille maximale de la file}
{
Nous proposons ici d'offrir un constructeur qui reçoit la taille maximale de la file et qui crée un tableau d'indices 0
à tailleMax (le tableau aura donc un élément de plus que la taille maximale de la file, nous allons expliquer
pourquoi). On remplit le tableau en ajoutant les éléments les uns à la suite des autres en retenant la position du
premier et du dernier via deux indices. Lorsqu'on ajoute un élément, la position du dernier va augmenter, et lorsqu'on
enlève un élément, cela revient à augmenter la position du premier, afin d'éviter de devoir retasser l'ensemble de la
file en début de tableau, ce qui serait une perte d'efficacité. }
{
\textit{Exemple}.}
{
Supposons qu'après la création de la file, les éléments 4, 3, 6 et 2 ont été ajoutés. L'indice du premier est 0 et celui
du dernier est 3.}
\begin{center}
\tablefirsthead{}
\tablehead{}
\tabletail{}
\tablelasttail{}
\begin{supertabular}{|m{1.171cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.232cm}|}
\hline
\centering{\sffamily 4} &
\centering{\sffamily 3} &
\centering{\sffamily 6} &
\centering{\sffamily 2} &
~
&
~
&
~
&
~
&
~
&
~
\\\hline
\end{supertabular}
\end{center}
{
On ajoute l'élément 7. L'indice du dernier est à présent 4.}
\begin{center}
\tablefirsthead{}
\tablehead{}
\tabletail{}
\tablelasttail{}
\begin{supertabular}{|m{1.171cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.232cm}|}
\hline
\centering{\sffamily 4} &
\centering{\sffamily 3} &
\centering{\sffamily 6} &
\centering{\sffamily 2} &
\centering{\sffamily 7} &
~
&
~
&
~
&
~
&
~
\\\hline
\end{supertabular}
\end{center}
{
On enlève un élément de la file. L'indice du premier vaut maintenant 1}
\begin{center}
\tablefirsthead{}
\tablehead{}
\tabletail{}
\tablelasttail{}
\begin{supertabular}{|m{1.171cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.206cm}|m{1.232cm}|}
\hline
~
&
\centering{\sffamily 3} &
\centering{\sffamily 6} &
\centering{\sffamily 2} &
\centering{\sffamily 7} &
~
&
~
&
~
&
~
&
~
\\\hline
\end{supertabular}
\end{center}
{
Ce mécanisme peut se faire de façon circulaire : arrivés en fin de tableau, les~indices premier et dernier repassent à
0. Lorsque premier et dernier sont égaux, la file n'a qu'un seul élément. Si cet élément est supprimé, l'incrémentation
de premier aura pour conséquence que l'indice premier sera d'une unité supérieur à l'indice dernier (en tenant compte
de la rotation des valeurs), et ce sera donc la condition correspondant à une file vide. Le tableau ne sera jamais
rempli au maximum pour pouvoir distinguer le cas d'une file vide et le cas d'une file pleine. Nous placerons donc dans
le tableau au maximum tailleMax éléments (en laissant un élément «~vide~» entre les indices dernier et premier). }
\section[Ex. 3. Le monte{}-charge]{\sffamily Ex. 3. Le monte-charge}
{
Un monte-charge de chantier assure le transport de personnes et de matériel entre deux niveaux. Lorsque le monte-charge
arrive à un étage, tous ses passagers en sortent. La charge maximale admise à la valeur MAX (donnée en paramètre).
Étant donné les risques liés à l'utilisation du monte-charge en surcharge, le poids de chacun des passagers et des
charges qu'ils transportent (outils, brouette de sable{\dots}) est vérifié avant l'entrée dans le monte-charge. }
{
Pour gérer l'embarquement dans le monte-charge, on souhaite faire appel à un algorithme «~embarquement~» qui détermine
combien de personnes qui se trouvent actuellement en file devant le monte-charge peuvent y entrer. }
{
Cet algorithme respectera l'ordre d'arrivée des personnes~et mettra à jour la file des personnes en attente qu'il aura
reçue en paramètre.}
\liststyleWWviiiNumxvi
\begin{enumerate}
\item {
Choisissez une représentation de données adaptée à la solution du problème et justifiez votre choix. }
\item {
Écrivez l'algorithme «~embarquement~»}
\item {
Écrivez l'algorithme «~arrivée~» qui ajoute à la file une personne d'un poids donné en paramètre.}
\item {
Quels cas doit-on envisager ?}
\end{enumerate}
\section[Ex. 4. A l{}'envers]{\sffamily Ex. 4. A l'envers}
{\color{black}
Écrire un module recevant en paramètre une file d'entiers. A l'issue de ce module, les valeurs de la file seront en
ordre inverse et débarrassées des éléments pairs. }
{\color{black}
\textit{Exemple.} \textit{Si le contenu de la file est le suivant :}}
{\centering\color{black}
1 $\rightarrow $ 0 $\rightarrow $ 4 $\rightarrow $ 25 $\rightarrow $ 20 $\rightarrow $ 11 $\rightarrow $ 3 $\rightarrow
$ 7 $\rightarrow $ 8 $\rightarrow $ 73 $\rightarrow $ 2 $\rightarrow $ 4
\par}
{\itshape\color{black}
son contenu sera après traitement : }
{\centering\color{black}
73 $\rightarrow $ 7 $\rightarrow $ 3 $\rightarrow $ 11 $\rightarrow $ 25 $\rightarrow $ 1
\par}
\bigskip
\clearpage
\bigskip
\begin{flushleft}
\tablefirsthead{}
\tablehead{}
\tabletail{}
\tablelasttail{}
\begin{supertabular}{m{10.14cm}m{5.8430004cm}}
{\sffamily\bfseries Chapitre 4~-- L'association}
~
&
\includegraphics[width=5.66cm,height=2.536cm]{a2012Logique2eme-img014.png} \\
\end{supertabular}
\end{flushleft}
\bigskip
\section[Introduction]{\sffamily Introduction}
{
Dans ce chapitre, nous considérons des ensembles de données possédant une \textbf{clé} (aussi appelée
\textbf{identifiant}). Par définition, \ la clé est unique pour chaque élément de \ l'ensemble. Vous connaissez déjà de
nombreux exemples par le cours de bases de données, citons~entre autres :}
\liststyleWWviiiNumxxiii
\begin{itemize}
\item {
le numéro d'étudiant, unique pour chaque étudiant de l'ESI}
\item {
le numéro de châssis d'un véhicule automobile}
\item {
le numéro de catalogue des produits vendus dans une grande surface}
\item {
le code postal des communes de Belgique, etc.}
\end{itemize}
\bigskip
{
Pour pouvoir stocker les éléments de ce type d'ensemble dans le cadre de processus qui requièrent des accès fréquents
aux données, nous devons recourir -- parmi les structures de données vues jusqu'ici -- au tableau ou à la liste (la
liste non chainée vue en 1\textsuperscript{ère} année). L'inconvénient de ces structures réside dans le fait de devoir
localiser les données par un indice, qui est dans la plupart des cas un numéro d'ordre arbitraire qui n'est pas
directement lié à la clé ; il faut donc toujours accompagner la structure choisie d'un outil de recherche, ce qui
implique un parcours des données pour chacune des opérations de bases telles que la modification, la consultation ou la
suppression d'un élément.}
\bigskip
{
Prenons l'exemple des étudiants de l'ESI dont l'identifiant est un entier de 5 chiffres (par ex. 35421). Si on stocke
les données dans un tableau par ordre alphabétique, il est évident que l'indice de la case où se trouve un étudiant
donné n'aura aucun rapport direct avec son numéro d'étudiant. De même si on trie les données sur les numéros
d'étudiant, rien ne permet de le localiser directement, si ce n'est dans ce cas que la recherche pourrait être
accélérée (par une recherche dichotomique par ex.). On pourrait aussi envisager de placer un étudiant directement dans
la case correspondant à son numéro d'étudiant (ainsi, l'étudiant 35421 serait dans la case 35421) mais ce n'est pas une
idée très heureuse~car elle exigerait d'utiliser un tableau énorme dont la majorité des cases seraient inutilisées (il
n'y a pas 35000 étudiants à l'ESI !) et de plus le tableau contiendrait de nombreux trous (il n'y a pas un étudiant
pour chacun des numéros dans un intervalle donné, certains numéros disparaissent par exemple suite à un abandon).}
\bigskip
{
Nous allons dans ce chapitre construire une structure qui permet de faire la liaison directe entre un élément et sa clé,
et qui nous dispensera du problème «~technique~» de devoir rechercher cet élément dans la structure. La connaissance de
sa clé devrait permettre de le localiser immédiatement par un algorithme de complexité minimale (en O(1) plutôt que en
O(n)).}
\section[]{\sffamily }
\section[Définition]{\sffamily Définition}
{
Une \textbf{association} (on dit aussi \textit{dictionnaire}~ou encore \textit{map}~selon la terminologie anglaise) lie
des éléments à leur clé (ou identifiant). Il s'agit d'une structure de données qui contient des couples (clé, valeur)
et qui autorise les opérations suivantes : stocker, retirer et modifier un élément à partir de sa clé, connaitre le
nombre d'éléments de l'ensemble (c'est-à-dire le nombre de couples), et obtenir la liste des clés des éléments présents
dans la structure.}
\section[Description orienté{}-objet]{\sffamily Description orienté-objet}
{
Nous allons définir une classe Map (pour des raisons pratiques, nous optons pour le nom anglais en raison de sa
brièveté) dont les méthodes réalisent les opérations citées ci-dessus. Les éléments contenus dans cette «~map~» sont
des couples (clé, valeur). Plus précisément ce sont des variables structurées dont les champs sont d'une part la clé
(de type K, le plus souvent un entier ou une chaine de caractère) et d'autre part la valeur (de type T quelconque). En
particulier, la clé peut être elle-même un champ de la valeur, ce qui peut paraître redondant, mais nécessaire pour le
fonctionnement de la classe.}
\bigskip
{\sffamily
\textbf{classe} Map<K, T>\ \ \ \ \ \ \ \ // K est le type de la clé }
{\sffamily
\ \ \ \ \ \ \ \ \ \ \ \ \ \ // et T celui de la valeur}
{\sffamily
\textbf{\ \ \ \ \ }\textbf{privé} :\ \ \ \ \ \ \ \ \ \ \ \ // choix à détailler plus tard}
{\sffamily
\textbf{\ \ \ \ \ }\textbf{public} :}
{\sffamily
\textbf{\ \ \ \ \ \ \ \ \ \ }\textbf{constructeur} Map<K, T>({\dots}) \ \ \ \ // initialise la
structure vide}
{\sffamily
\textbf{\ \ \ \ \ \ \ \ \ \ }\textbf{méthode} setÉlément(clé : K, val : T)\ \ // ajoute le couple de clé donnée }
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ getValeur(clé : K) }$\rightarrow $
\textsf{T\ \ \ \ // retourne la valeur associée à la clé}}
{\sffamily
\textbf{\ \ \ \ \ \ \ \ \ \ }\textbf{méthode} supprimer(clé : K)\ \ \ \ // retire le couple associé à la clé}
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ contient(clé : K) }$\rightarrow $
\textsf{booléen\ \ \ \ // indique si le couple de clé donnée est }}
{\sffamily
\ \ \ \ \ \ \ \ \ \ // présent}
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ taille( ) }$\rightarrow $\textsf{
entier\ \ \ \ \ \ // retourne le nombre de couples}}
{
\textsf{\textbf{\ \ \ \ \ \ \ \ \ \ }}\textsf{\textbf{méthode}}\textsf{ listeClés( ) }$\rightarrow $\textsf{
Liste<K>\ \ \ \ // retourne la liste des clés présentes}}
{\sffamily\bfseries
fin classe}
\subsection[La méthode setÉlément peut éventuellement écraser une valeur précédente si la clé était déjà présente. Les
méthodes getValeur et supprimer génèrent un message d{}'erreur si la clé en paramètre est absente de l{}'ensemble. La
dernière méthode est nécessaire pour pouvoir parcourir les éléments de l{}'ensemble. En effet, sa structure interne
étant un attribut privé inconnu à l{}'extérieur de la classe, il est nécessaire d{}'avoir un outil donnant la liste des
clés présentes. En parcourant la liste et en utilisant la méthode getValeur, on pourra ainsi passer en revue tous les
éléments de l{}'association. Noter que la liste retournée n{}'est pas forcément dans l{}'ordre des clés, c{}'est une
limitation de cette structure.]{ La méthode setÉlément peut éventuellement écraser une valeur
précédente si la clé était déjà présente. Les méthodes getValeur et supprimer génèrent un message d'erreur si la clé en
paramètre est absente de l'ensemble. La dernière méthode est nécessaire pour pouvoir parcourir les éléments de
l'ensemble. En effet, sa structure interne étant un attribut privé inconnu à l'extérieur de la classe, il est
nécessaire d'avoir un outil donnant la liste des clés présentes. En parcourant la liste et en utilisant la méthode
getValeur, on pourra ainsi passer en revue tous les éléments de l'association. Noter que la liste retournée n'est pas
forcément dans l'ordre des clés, c'est une limitation de cette structure.}
\section[Exemple d{}'utilisation]{\sffamily Exemple d'utilisation}
\subsection[Illustrons par un exemple l{}'utilité de la classe Map. Supposons qu{}'on veuille faire des statistiques sur
les marques de voitures d{}'un grand parc automobile. On voudrait connaître le nombre de véhicules pour chacune des
marques présentes. Les données sont contenues dans un fichier fichAuto dont chaque enregistrement de type Voiture
contient les champs marque (chaine), modèle (chaine), immatriculation (chaine), et d{}'autres données qui ne sont pas
utiles ici.]{ \textmd{Illustrons par un exemple l'utilité de la classe Map. Supposons qu'on
veuille faire des statistiques sur les marques de voitures d'un grand parc automobile. On voudrait connaître le nombre
de véhicules pour chacune des marques présentes. Les données sont contenues dans un fichier }fichAuto\textmd{ dont
chaque enregistrement de type }Voiture\textmd{ contient les champs }marque\textmd{ (chaine), }modèle\textmd{ (chaine),
}immatriculation\textmd{ (chaine), et d'autres données qui ne sont pas utiles ici.}}
\subsection[Ecrivons une première version sans utiliser la classe Map. Nous avons besoin d{}'un compteur associé à
chacune des marques de voitures. Il est possible d{}'utiliser un tableau, mais avec l{}'inconvénient de ne pas savoir à
l{}'avance le nombre de marques différentes (ce qui pourrait se solutionner en déclarant le tableau avec une taille
raisonnablement grande dans ce contexte, 500 par exemple). Nous allons plutôt opter pour une liste (classe Liste), dont
les éléments seront une structure eltListe contenant les champs marque (chaine) et cpt (entier). La démarche est
simple~: lorsqu{}'une nouvelle marque est rencontrée, il faut ajouter un compteur dans la liste initialisé à 1~; si la
marque a déjà été rencontrée, il faut retrouver le compteur associé à cette marque et l{}'incrémenter. Un module de
recherche est donc indispensable pour le bon fonctionnement.]{ \textmd{Ecrivons une première
version sans utiliser la classe Map. Nous avons besoin d'un compteur associé à chacune des marques de voitures. Il est
possible d'utiliser un tableau, mais avec l'inconvénient de ne pas savoir à l'avance le nombre de marques différentes
(ce qui pourrait se solutionner en déclarant le tableau avec une taille raisonnablement grande dans ce contexte, 500
par exemple). Nous allons plutôt opter pour une liste (classe Liste), dont les éléments seront une structure
}eltListe\textmd{ contenant les champs }marque\textmd{ (chaine) et }cpt\textmd{ (entier). La démarche est simple :
lorsqu'une nouvelle marque est rencontrée, il faut ajouter un compteur dans la liste initialisé à 1 ; si la marque a
déjà été rencontrée, il faut retrouver le compteur associé à cette marque et l'incrémenter. Un module de recherche est
donc indispensable pour le bon fonctionnement.}}
\bigskip
{\sffamily
\textbf{module} statVoitures(fichAuto : FichierEntrée de Voiture)}
{\sffamily
\ \ i, ind : entier}
{\sffamily
\ \ enr : Voiture}
{\sffamily
\ \ elt : eltListe}
{\sffamily
\ \ listeCpt : Liste<eltListe>}
{
\textsf{\ \ listeCpt~}[F0DF?]\textsf{ nouvelle Liste<eltListe>( )}}
{\sffamily
\ \ fichAuto.ouvrir( )}
{
\textsf{\ \ enr }[F0DF?]\textsf{ fichAuto.lire( )}}
{\sffamily
\ \ \textbf{tant que} NON fichAuto.EOF( ) \textbf{faire}}
{
\textsf{\textbf{\ \ \ \ }}\textsf{ind }[F0DF?]\textsf{ recherche(listeCpt, enr.marque)}}
{\sffamily
\ \ \ \ \textbf{si} ind = 0 \textbf{alors}\ \ // la marque n'a pas encore été comptée}
{
\textsf{\ \ \ \ \ \ elt.marque }[F0DF?]\textsf{ enr.marque}}
{
\textsf{\ \ \ \ \ \ elt.cpt }[F0DF?]\textsf{ 1}}
{\sffamily
\ \ \ \ \ \ listeCpt.ajouter(elt)}
{\sffamily
\ \ \ \ \textbf{sinon\ \ \ \ }\ \ // la marque est présente dans la liste}
{
\textsf{\ \ \ \ \ \ }\foreignlanguage{english}{\textsf{elt }}[F0DF?]\foreignlanguage{english}{\textsf{
listeCpt.get(ind)}}}
{
\foreignlanguage{english}{\textsf{\ \ \ \ \ \ elt.cpt }}[F0DF?]\foreignlanguage{english}{\textsf{ elt.cpt + 1}}}
{\sffamily
\foreignlanguage{english}{\ \ \ \ \ \ }listeCpt.set(ind, elt)}
{\sffamily
\ \ \ \ \textbf{fin si}}
{
\textsf{\ \ \ \ enr }[F0DF?]\textsf{ fichAuto.lire( )}}
{\sffamily
\ \ \textbf{fin tant}}
{\sffamily
\ \ fichAuto.fermer( )}
{\sffamily
\ \ \textbf{pour }i \textbf{de} 1 \textbf{à} listeCpt.taille( ) \textbf{faire}}
{\sffamily
\ \ \ \ \textbf{écrire} listeCpt.get(i).marque, listeCpt.get(i).cpt}
{\sffamily
\ \ \textbf{fin pour}}
{\sffamily\bfseries
fin module}
\bigskip
{
\textsf{\textbf{module}}\textsf{ recherche(liste : Liste<eltListe>, marque : chaine)
}[F0E0?]\textsf{ entier}}
{\sffamily
\ \ // recherche dans la liste l'élément correspondant à la marque en paramètre}
{\sffamily
\ \ // et retourne sa position dans la liste, 0 s'il ne s'y trouve pas}
{\sffamily
\ \ i : entier}
{\sffamily
\ \ trouvé : booléen}
{
\textsf{\ \ trouvé }[F0DF?]\textsf{ faux}}
{
\textsf{\ \ i }[F0DF?]\textsf{ 0}}
{\sffamily
\ \ \textbf{tant que} NON trouvé ET i < liste.taille( ) \textbf{faire}}
{
\textsf{\ \ \ \ i }[F0DF?]\textsf{ i + 1}}
{
\textsf{\textbf{\ \ \ \ }}\textsf{trouvé }[F0DF?]\textsf{ liste.get(i).marque = marque}}
{\sffamily\bfseries
\ \ fin tant\ \ }
{\sffamily
\textbf{\ \ si }trouvé\textbf{ alors}}
{\sffamily
\textbf{\ \ \ \ retourner} i}
{\sffamily\bfseries
\ \ sinon}
{\sffamily
\textbf{\ \ \ \ retourner} 0}
{\sffamily\bfseries
\ \ finsi}
{\sffamily\bfseries
fin}
\bigskip
{
Avec la classe Map, le code se simplifie considérablement : nous sommes débarassés du module de recherche, et du souci
de connaître à quel endroit se trouve le compteur associé à une marque donnée. Les valeurs seront ici les compteurs, et
les clés les marques de voitures. On utilise donc une Map<chaine, entier> :}
\bigskip
{\sffamily
\textbf{module} statVoitures(FichAuto : FichierEntrée de Voiture)}
{\sffamily
\ \ enr : Voiture}
{\sffamily
\ \ i : entier}
{\sffamily
\ \ liste : Liste<chaine>}
{\sffamily
\ \ compteurs : Map <chaine, entier>}
{
\textsf{\ \ compteurs }[F0DF?]\textsf{ nouvelle Map<chaine, entier>( )}}
{\sffamily
\ \ fichAuto.ouvrir( )}
{
\textsf{\ \ enr }[F0DF?]\textsf{ fichAuto.lire( )}}
{\sffamily
\ \ \textbf{tant que} NON fichAuto.EOF( ) \textbf{faire}}
{\sffamily
\textbf{\ \ \ \ si} compteurs.contient(enr.marque) \textbf{alors }}
{\sffamily
\textbf{\ \ \ \ \ \ }// la marque est déjà présente dans la Map}
{\sffamily
\ \ \ \ \ \ compteurs.setÉlément(enr.marque, compteurs.getValeur(enr.marque) + 1)}
{\sffamily
\ \ \ \ \textbf{sinon}}
{\sffamily
\textbf{\ \ \ \ }\ \ // la marque n'est pas encore dans la Map}
{\sffamily
\ \ \ \ \ \ compteurs.setÉlément(enr.marque, 1)}
{\sffamily
\ \ \ \ \textbf{fin si}}
{
\textsf{\ \ \ \ enr }[F0DF?]\textsf{ fichAuto.lire( )}}
{\sffamily
\ \ \textbf{fin tant}}
{\sffamily
\ \ fichAuto.fermer( )}
{
\textsf{\ \ liste }[F0DF?]\textsf{ compteurs.listeClés( )}}
{\sffamily
\ \ \textbf{pour }i \textbf{de} 1 \textbf{à} liste.taille( ) \textbf{faire}}
{\sffamily
\ \ \ \ \textbf{écrire} liste.get(i), compteurs.getValeur(liste.get(i))}
{\sffamily
\ \ \textbf{fin pour}}
{\sffamily\bfseries
fin module}
\section[Implémentation]{\sffamily Implémentation}
{
On voit par l'exemple précédent que l'association apparaît de l'extérieur comme un ensemble non ordonné, une grande
boîte dans laquelle on introduit les couples (clé, valeur) et de laquelle on peut les récupérer très facilement.
Comment cela fonctionne-t-il ? Pour implémenter une association, il est bien sûr possible d'utiliser les structures
déjà connues :}
\liststyleWWviiiNumiii
\begin{itemize}
\item {
un tableau (trié ou non) ou une liste dont les éléments sont les couples (clé, valeur) comme dans l'exemple des
statistiques des marques de voitures}
\item {
une liste chainée (triée ou non)}
\item {
un arbre binaire ordonné sur les clés (voir chapitre sur les arbres)}
\end{itemize}
{
Utiliser une de ces structures comme attribut de la classe reviendrait dès lors à camoufler à l'intérieur de la classe
un algorithme de recherche tel que celui qui apparaît explicitement dans l'exemple ci-dessus, ce qui ne serait pas un
réel progrès quant à l'efficacité.}
{
Il existe une structure particulière très efficace, nommée \textit{table de hachage}, qui utilise un tableau pour
stocker les éléments, et la position d'un élément dans ce tableau se retrouve très rapidement en utilisant une
\textit{fonction de hachage}.}
\section[La fonction de hachage]{\sffamily La fonction de hachage}
{
Une \textit{fonction de} \textit{hachage} transforme une clé en un «~petit~» entier. Le but est d'obtenir par cette
fonction (que nous noterons \textit{h}(\textit{x}) des valeurs entre 1 (ou 0) et une valeur maximale N, et qui seront
réparties le plus uniformément possible dans cet intervalle. Le choix de la fonction de hachage dépend du type de clé
et aussi de la taille des éléments à classer. }
{
Cependant, il est courant que l'ensemble d'arrivée de la fonction soit plus petit que l'ensemble des clés, et il est
donc inévitable que deux clés différentes donnent le même nombre après hachage. Dans ce cas on parle de «~collision~».
Lors du choix de la fonction de hachage, il faut \ également chercher à minimiser ces collisions, en vue d'un
fonctionnement performant de la classe.}
{\bfseries
Exemples}
\liststyleWWviiiNumiv
\begin{itemize}
\item {
Prenons l'ensemble des étudiants de l'ESI, avec comme clé le numéro d'étudiant de 5 chiffres. La fonction
\textit{h}(\textit{x}) = \textit{x} DIV 1000 ne serait pas un bon choix car elle donnerait un nombre réduit de valeurs
(comprises actuellement entre 35 et 40), à partir d'un ensemble de plusieurs centaines d'étudiants. La fonction
\textit{h}(\textit{x})\textit{ }=\textit{ x} MOD 100 est déjà bien meilleure, elle donnerait des valeurs entre 0 et 99.
Il y aura bien sûr des collisions, vu que les étudiants de numéros 37156 et 38956 seraient «~hachés~» de la même
façon.}
\item {
Pour les codes postaux des villes de Belgique, on pourrait prendre la fonction \textit{h}(\textit{x}) = \textit{x} DIV
10. Elle donnerait un ensemble de valeurs entre 100 et 999 où les collisions seraient peu nombreuses (vu que la plupart
des codes se terminent par 0).}
\end{itemize}
\section[La table de hachage]{\sffamily La table de hachage}