Queue (file)
Dernière mise à jour
Une file a deux extrémités actives. Les nouvelles valeurs rejoignent la queue de la file, et les valeurs sortent par la tête : celle qui a attendu le plus longtemps est donc servie en premier. C'est cela, FIFO, et c'est exactement le comportement d'une file d'attente à un guichet : se placer au bout et être servi à l'avant, voilà ce qui rend l'attente équitable. Lancez la lecture ci-dessus et regardez les valeurs entrer d'un côté et sortir de l'autre.
Comme chaque extrémité est suivie par son propre indice ou pointeur, les deux opérations sont en O(1) et aucune ne décale le reste des données. C'est pourquoi les files se trouvent sous tout ce qui traite le travail dans l'ordre d'arrivée : travaux d'impression, files de tâches et de messages, tampons de requêtes, et le parcours en largeur, qui visite un graphe niveau par niveau précisément parce qu'il garde sa frontière dans une file. Déplacez l'extrémité de retrait vers l'arrière et vous obtenez un Stack (pile).
Complexité en temps et en espace
Pour une file fondée sur un tampon circulaire ou sur une liste chaînée, les deux implémentations classiques :
| Opération | Complexité | Remarques |
|---|---|---|
| Enfiler | O(1) | Écrire en queue et avancer l'indice de queue. |
| Défiler | O(1) | Lire en tête et avancer l'indice de tête, sans aucun décalage. |
| Peek (tête) | O(1) | Lit la valeur en tête sans la retirer. |
| Recherche | O(n) | Ce n'est pas le rôle d'une file : il faut la vider pour regarder dedans. |
| Espace | O(n) | Un emplacement par valeur en attente. |
Étape par étape
| Étape | Ce qui se passe |
|---|---|
| 1 | La file démarre vide, la tête et la queue pointant sur le même emplacement. |
| 2 | Enfiler écrit la valeur en queue, puis avance la queue d'un cran. |
| 3 | Chaque nouvel enfilement se place derrière les valeurs déjà en attente. |
| 4 | Défiler lit la valeur en tête, puis avance la tête d'un cran. |
| 5 | La valeur renvoyée est toujours celle qui a attendu le plus longtemps. |
| 6 | Quand la tête rejoint la queue, la file est de nouveau vide, et continuer à défiler est une erreur. |
Exemple détaillé
Enfilement de 3, 7, 5 puis vidage de la file :
| Opération | File (de la tête à la queue) | Renvoie |
|---|---|---|
enqueue(3) | [3] | rien |
enqueue(7) | [3, 7] | rien |
enqueue(5) | [3, 7, 5] | rien |
dequeue() | [7, 5] | 3, la valeur la plus ancienne |
dequeue() | [5] | 7 |
dequeue() | [] | 5, la plus récente, en dernier |
Quand utiliser une file
| À utiliser quand | À éviter quand |
|---|---|
| Le travail doit être traité dans l'ordre d'arrivée : files de tâches, tampons de requêtes, spouleurs d'impression | Vous voulez d'abord l'élément le plus récent, ce qui est un Stack (pile) |
| Vous explorez niveau par niveau, comme le fait le parcours en largeur | Les éléments doivent être servis par priorité plutôt que par ordre d'arrivée, où un tas convient |
| Un producteur et un consommateur avancent à des vitesses différentes et ont besoin d'un tampon entre eux | Vous devez chercher ou indexer au milieu des données |
Vous voulez une insertion et un retrait O(1) sans décaler les éléments | Vous l'implémenteriez en décalant un tableau à chaque défilement, ce qui la rend O(n) |
Code de Queue
Une implémentation propre et exécutable de Queue en Python, JavaScript, Java, C++, C. Choisissez un langage, copiez le code ou ouvrez-le préchargé dans le Playground Coddy.
Code de Queue en Python
1from collections import deque2
3queue = deque()4
5# Enqueue three values at the rear6for value in [3, 7, 5]:7 queue.append(value)8 print(f"enqueue {value} -> {list(queue)}")9
10# Dequeue them from the front: first in, first out11while queue:12 value = queue.popleft()13 print(f"dequeue {value} -> {list(queue)}")14
15print("empty:", len(queue) == 0)Code de Queue en JavaScript
1// A plain array makes dequeue O(n): shift() moves every element left.2// Track a head index instead, the fix the queue article describes.3const queue = { items: [], head: 0 };4
5function enqueue(value) {6 queue.items.push(value);7}8
9function dequeue() {10 const value = queue.items[queue.head];11 queue.items[queue.head] = undefined; // free the slot12 queue.head += 1;13 // Reclaim space once the consumed prefix dominates.14 if (queue.head * 2 >= queue.items.length) {15 queue.items = queue.items.slice(queue.head);16 queue.head = 0;17 }18 return value;19}20
21const size = () => queue.items.length - queue.head;22
23for (const value of [3, 7, 5]) {24 enqueue(value);25 console.log(`enqueue ${value} -> size ${size()}`);26}27
28// Dequeue from the front: first in, first out, amortized O(1)29while (size() > 0) {30 console.log(`dequeue ${dequeue()} -> size ${size()}`);31}32
33console.log('empty:', size() === 0);Code de Queue en Java
1import java.util.ArrayDeque;2import java.util.Queue;3
4public class Main {5 public static void main(String[] args) {6 Queue<Integer> queue = new ArrayDeque<>();7
8 // Enqueue three values at the rear9 for (int value : new int[] {3, 7, 5}) {10 queue.add(value);11 System.out.println("enqueue " + value + " -> " + queue);12 }13
14 // Dequeue them from the front: first in, first out15 while (!queue.isEmpty()) {16 int value = queue.remove();17 System.out.println("dequeue " + value + " -> " + queue);18 }19
20 System.out.println("empty: " + queue.isEmpty());21 }22}Code de Queue en C++
1#include <iostream>2#include <queue>3
4int main() {5 std::queue<int> queue;6
7 // Enqueue three values at the rear8 for (int value : {3, 7, 5}) {9 queue.push(value);10 std::cout << "enqueue " << value << " -> size " << queue.size() << "\n";11 }12
13 // Dequeue them from the front: first in, first out14 while (!queue.empty()) {15 int value = queue.front();16 queue.pop();17 std::cout << "dequeue " << value << " -> size " << queue.size() << "\n";18 }19
20 std::cout << "empty: " << std::boolalpha << queue.empty() << "\n";21 return 0;22}Code de Queue en C
1#include <stdio.h>2
3#define CAP 164
5int queue[CAP];6int front = 0;7int rear = 0; /* index of the next free slot */8
9int main(void) {10 int values[3] = {3, 7, 5};11
12 /* Enqueue three values at the rear */13 for (int i = 0; i < 3; i++) {14 queue[rear++] = values[i];15 printf("enqueue %d -> size %d\n", values[i], rear - front);16 }17
18 /* Dequeue them from the front: first in, first out */19 while (front < rear) {20 int value = queue[front++];21 printf("dequeue %d -> size %d\n", value, rear - front);22 }23
24 printf("empty: %d\n", front == rear);25 return 0;26}FAQ sur la file
Que signifie FIFO ?
Quelle est la différence entre une file et une pile ?
O(1) ; une file retire par la tête (FIFO), une pile retire par l'extrémité où elle a ajouté (LIFO). Pour le reste, leurs tableaux de complexité sont identiques.Quelles sont les principales opérations d'une file ?
enqueue ajoute une valeur en queue, dequeue retire et renvoie la valeur en tête, peek (ou front) lit la tête sans la retirer, et is_empty indique s'il reste quelque chose en attente. Les quatre sont en O(1).Pourquoi défiler est-il lent si j'utilise un simple tableau ?
O(n). Les vraies implémentations l'évitent avec un tampon circulaire qui avance un indice de tête, ou avec une liste chaînée munie d'un pointeur de tête. Le collections.deque de Python et l'ArrayDeque de Java le font pour vous, alors que list.pop(0) non.Qu'est-ce qu'une file circulaire ?
n continue de fonctionner indéfiniment au lieu de sortir du tableau.