Les files
Retirer la première de 1000 valeurs d'un tableau JavaScript avec shift déplace les 999 autres ; un tampon circulaire fait le même travail en une étape.
Premier entré, premier sorti
Une file, c'est une file d'attente devant un comptoir. Les gens arrivent par l'arrière et sont servis par l'avant : celui qui est arrivé en premier repart en premier. La règle est premier entré, premier sorti (FIFO en anglais). Les deux opérations sont enfiler (enqueue), qui ajoute une valeur à l'arrière, et défiler (dequeue), qui retire la valeur de l'avant. Dans les notes du cours 6.006 du MIT, une file est l'interface de séquence limitée à insert last(x) et delete first().
Les files sont partout où il faut traiter des tâches dans l'ordre d'arrivée : documents en attente d'une imprimante, touches en attente d'un programme, messages en attente d'un serveur. Le parcours en largeur, vu dans le cours d'algorithmique, garde dans une file les cases qu'il lui reste à visiter, et c'est exactement pour cela qu'il explore par anneaux à égale distance.
La solution facile et son coût caché
En JavaScript, la file évidente est un tableau : push pour enfiler à l'arrière et shift pour défiler à l'avant. Ça marche, et pour des files courtes, c'est très bien. Mais regarde ce que fait shift. MDN indique qu'il « décale toutes les valeurs de 1 vers la gauche », et la spécification ECMAScript l'écrit comme une boucle qui copie l'élément k à la position k − 1 pour chaque k. Le début d'un tableau est le côté coûteux, comme l'a montré la première unité. Défiler une file de n valeurs coûte 1 lecture plus n − 1 déplacements : une file de 1000 valeurs coûte donc 1000 étapes par défilement. (Les moteurs peuvent utiliser des raccourcis en interne, mais la spécification ne promet rien.)
Si tu enfiles 5 valeurs dans un tableau vide puis que tu les défiles toutes les 5, les enfilements coûtent 5 étapes et les défilements 5 + 4 + 3 + 2 + 1 = 15, soit 20 en tout. L'essentiel de ce travail consiste à déplacer des valeurs qu'on ne retire même pas.
Ne pas déplacer les valeurs, déplacer l'avant
La solution consiste à ne plus déplacer les valeurs et à retenir plutôt où se trouve l'avant. On garde un indice appelé head. Défiler lit la valeur à head et ajoute 1 à head ; rien d'autre ne bouge. Le problème, c'est que les cases avant head sont perdues. Un tampon circulaire (ring buffer) les réutilise : le tableau a un nombre fixe de cases, disons 8, et les positions font le tour, si bien que la case après 7 est 0. On stocke head et size. L'enfilement suivant va dans la case (head + size) mod 8, et un défilement prend la case head et fait passer head à (head + 1) mod 8. Les deux opérations coûtent 1 étape. Le prix à payer est une capacité fixe : quand size atteint 8, la file est pleine, sauf si l'on recopie tout dans un anneau plus grand comme le ferait un tableau dynamique.
Fais glisser pour tourner. Fais défiler ou pince pour zoomer.
| File de n valeurs | Enfiler | Défiler |
|---|---|---|
| Tableau avec push et shift | 1 (amorti) | 1 lecture + (n − 1) déplacements |
| Tableau avec un indice head | 1 (amorti) | 1, mais les cases de devant sont perdues |
| Tampon circulaire de taille fixe | 1, ou pleine | 1 |
Laquelle utiliser ? Pour une file qui ne contient jamais plus de quelques dizaines de valeurs, push et shift sont courts et clairs, et les déplacements ne coûtent presque rien. Pour une file par laquelle passent des milliers d'éléments, comme les cases d'un grand parcours en largeur, un indice head ou un tampon circulaire maintient chaque défilement à une étape, et la différence augmente avec la longueur de la file.
| FIFO | Premier entré, premier sorti : les valeurs sortent dans l'ordre où elles sont arrivées. |
| Enfiler / défiler | Ajouter à l'arrière / retirer à l'avant. |
| shift | Retire la première valeur du tableau et décale toutes les autres d'une case vers la gauche. |
| Tampon circulaire | Un tableau fixe utilisé en cercle : la prochaine case libre est (head + size) mod capacité. |
- Dans quel ordre une file rend-elle les valeurs ?
- Premier entré, premier sorti
- Dernier entré, premier sorti
- La plus grande d'abord
- Dans un ordre aléatoire
- Enfile A, B, C. Défile une fois. Enfile D. Défile maintenant jusqu'à ce que la file soit vide. Range ces valeurs dans l'ordre.
- Avec push et shift, combien d'étapes prend un défilement sur une file de 4 valeurs (1 lecture plus les déplacements) ?
- Même méthode, une file de 1000 valeurs : combien d'étapes pour un défilement ?
- On part d'un tableau vide. On enfile 5 valeurs avec push, puis on les défile toutes les 5 avec shift. Combien d'étapes au total ?
- Un tampon circulaire a 8 cases (de 0 à 7), head = 6 et size = 3. Quelle case utilise le prochain enfilement ?
- Combien d'étapes prend un défilement dans un tampon circulaire, quel que soit le nombre de valeurs qu'il contient ?
- Un anneau fixe de 8 cases contient 8 valeurs. Que se passe-t-il lors d'un enfilement ?
- Il écrase la valeur de l'avant
- La file est pleine et la valeur est refusée
- Il décale chaque valeur vers la gauche
- Il trie les valeurs
- Quel parcours du cours d'algorithmique garde ses cases en attente dans une file ?
- La recherche dichotomique
- Le parcours en largeur
- Le parcours en profondeur
- La recherche linéaire
- Dans le vocabulaire du MIT 6.006, quelles deux opérations de séquence une file utilise-t-elle ?
- insert last et delete last
- insert last et delete first
- insert first et delete first
- get at et set at
- Une file suit la règle premier entré, premier sorti : on enfile à l'arrière, on défile à l'avant.
- shift déplace toutes les valeurs restantes : défiler parmi n valeurs coûte donc n étapes.
- Un indice head ou un tampon circulaire ramène le défilement à 1 étape.
- Dans un anneau de taille c, la prochaine case libre est (head + size) mod c.
Sources de ce cours (11)
- MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
- lecture notes 2 Data Structures (interface vs data structure, Sequence and Set interfaces, stack = insert_last/delete_last, queue = insert_last/delete_first, array, linked list, dynamic array, amortized Θ(1) append)
- 4 Hashing (chaining, pigeonhole collisions, chain length n/m)
- 6 Binary Trees Part 1 (height, traversal order, O(h) operations) and 7 Binary Trees Part 2: AVL (Adelson-Velsky and Landis, 1962) at ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes
- MDN Web Docs, Array.prototype.shift (shifts all values left by 1)
- Array.prototype.unshift, Map (insertion order, Map vs Object, spec requires sublinear average access) and Set (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects)
- ECMAScript 2025 Language Specification (tc39.es/ecma262)
- 24.1 Map Objects and 24.2 Set Objects ("must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements")
- Array.prototype.shift steps (Repeat, while k < len: move element k to k - 1)
- D. E. Knuth, The Art of Computer Programming vol. 3 (2nd ed. 1998) section 6.4 History (H. P. Luhn, IBM internal memorandum January 1953, hashing with chaining; digit pairs added mod 10, 31415926 -> 4548) via gwern.net copy, and IEEE Spectrum, "Hans Peter Luhn and the Birth of the Hashing Algorithm" (2018)
- "A brief history of the stack", SIGCIS (sigcis.org/files/A brief history.pdf: Bauer and Samelson applied for the patent in 1957, US 3,047,228 granted July 31, 1962; IPL list processing by Newell, Simon and Shaw at RAND 1956) and Wikipedia, Information Processing Language (Newell, Shaw, Simon, RAND and Carnegie Institute of Technology, about 1956).
Consulté le: 2026-10-18