L'Art de la Programmation - Pile et File
Table of Contents
- 🍽️ Introduction
- 🧱 Container Data Structures
- 🧾 Lists
- 📚 Arrays
- 🔗 Linked Structures
- 🗂️ New Container Data Structures
- 💡 Stack
- 🔄 LIFO Principle
- ⚙️ Operations
- 📝 Implementation
- 🧺 Queue
- 🔄 FIFO Principle
- ⚙️ Operations
- 📝 Implementation
- 🔍 Comparing Stack and Queue
- 🤔 When to Use Stack
- 🤔 When to Use Queue
- 💻 Demo: Stack in Action
- ❗ Example Program for Palindrome Checking
- ⌨️ Code Explanation
- 💻 Demo: Queue in Action
- ❗ Example Program for Print Queue
- ⌨️ Code Explanation
- 👌 Conclusion
🍽️ Introduction
Bienvenue sur cet article qui porte sur les structures de données de type conteneur en programmation. Dans cet article, nous explorerons spécifiquement les structures de données suivantes : la liste, le tableau, la structure liée, la pile et la file. Chacune de ces structures a des caractéristiques uniques qui les rendent utiles dans différents cas d'utilisation. Nous commencerons par comprendre ce qu'est une structure de données et pourquoi il est important de les utiliser. Ensuite, nous examinerons de plus près chacune des structures de données mentionnées ci-dessus, en expliquant comment elles fonctionnent, quelles sont leurs opérations clés et comment les implémenter dans un programme. Enfin, nous comparerons la pile et la file et discuterons des situations dans lesquelles il est préférable de les utiliser. Prêt à plonger dans le monde fascinant des structures de données ? Allons-y !
🧱 Container Data Structures
Avant de plonger dans les structures de données spécifiques, il est essentiel de comprendre ce qu'est une structure de données de type conteneur. En informatique, une structure de données est un moyen de stocker et d'organiser des données de manière efficace pour faciliter leur manipulation et leur utilisation ultérieure. Un conteneur est une structure de données qui permet de regrouper des éléments de données individuels. Il existe plusieurs types de structures de données de type conteneur, dont les listes, les tableaux et les structures liées. Examinons chacun d'entre eux en détail.
🧾 Lists
Une liste est l'une des structures de données les plus couramment utilisées. Elle permet de stocker une collection d'éléments de données, qui peuvent être de types différents, à l'intérieur d'une seule structure. Par exemple, une liste peut contenir des entiers, des chaînes de caractères et d'autres objets. Les éléments d'une liste sont généralement accessibles par leur position ou leur indice.
📚 Arrays
Un tableau est également une structure de données couramment utilisée. Contrairement à une liste, un tableau ne peut stocker que des éléments de données du même type. Les éléments d'un tableau sont également accessibles par leur position ou leur indice.
🔗 Linked Structures
Une structure liée est une autre forme de structure de données de type conteneur. Elle est constituée d'un ensemble d'éléments appelés nœuds, qui sont liés les uns aux autres à l'aide de pointeurs. Chaque nœud contient des données et un pointeur vers le nœud suivant. Cette structure permet de créer des listes chaînées, des piles et des files, qui seront explorées plus en détail dans les sections suivantes.
🗂️ New Container Data Structures
Maintenant que nous avons une compréhension de base des structures de données de type conteneur, il est temps d'explorer deux nouvelles structures : la pile et la file. Ces deux structures sont basées sur le concept de listes et offrent des fonctionnalités spécifiques et limitées.
💡 Stack
Une pile est une structure de données très simple, basée sur le principe LIFO (Last In, First Out). Cela signifie que le dernier élément ajouté à la pile est le premier à en sortir. En d'autres termes, les éléments sont empilés les uns sur les autres et seul l'élément du dessus de la pile est visible et accessible.
🔄 LIFO Principle
Le principe LIFO (Last In, First Out) est le fondement de la pile. Il définit l'ordre dans lequel les éléments sont ajoutés et retirés de la pile. Lorsque de nouveaux éléments sont ajoutés à la pile, ils sont "poussés" vers le bas de la pile. Lorsque des éléments sont retirés de la pile, seul l'élément du dessus est "dépilé", ce qui signifie qu'il est supprimé de la pile.
⚙️ Operations
Pour implémenter une pile, nous avons besoin de trois opérations principales :
- Push : Ajoute un élément au sommet de la pile.
- Pop : Retire l'élément du sommet de la pile.
- Top : Renvoie la valeur de l'élément situé au sommet de la pile, sans le retirer.
Il est important de noter que seule l'opération de push permet d'ajouter des éléments à la pile, car elle respecte le principe LIFO. Les autres opérations ne permettent pas d'accéder à des éléments spécifiques situés en dessous du sommet de la pile.
📝 Implementation
Pour mettre en œuvre une pile, nous pouvons utiliser un tableau ou une structure liée. Dans cet exemple, nous utiliserons un tableau statique. Voici une implémentation simple d'une pile en utilisant un tableau :
function initStack() {
const stack = {
elements: [],
count: 0,
maxSize: 100,
};
return stack;
}
function push(stack, item) {
if (stack.count >= stack.maxSize) {
throw new Error('Stack overflow');
}
stack.elements[stack.count] = item;
stack.count++;
}
function pop(stack) {
if (stack.count === 0) {
throw new Error('Stack underflow');
}
stack.count--;
return stack.elements[stack.count];
}
function top(stack) {
if (stack.count === 0) {
throw new Error('Stack is empty');
}
return stack.elements[stack.count - 1];
}
function isEmpty(stack) {
return stack.count === 0;
}
function isFull(stack) {
return stack.count === stack.maxSize;
}
// Example usage:
const stack = initStack();
push(stack, 10);
push(stack, 20);
push(stack, 30);
console.log(top(stack)); // Output: 30
console.log(pop(stack)); // Output: 30
console.log(pop(stack)); // Output: 20
console.log(isEmpty(stack)); // Output: false
console.log(isFull(stack)); // Output: false
🧺 Queue
Une file est une autre structure de données basée sur le principe FIFO (First In, First Out). Cela signifie que le premier élément ajouté à la file est le premier à en sortir. En d'autres termes, les éléments sont enfilés à l'arrière de la file et retirés depuis l'avant de la file.
🔄 FIFO Principle
Le principe FIFO (First In, First Out) définit l'ordre dans lequel les éléments sont ajoutés et retirés de la file. Les nouveaux éléments sont ajoutés à l'arrière de la file, tandis que les éléments sont retirés depuis l'avant de la file. Cela garantit que les éléments sont traités dans l'ordre dans lequel ils sont arrivés.
⚙️ Operations
Pour implémenter une file, nous avons besoin de deux opérations principales :
- Enqueue : Ajoute un élément à l'arrière de la file.
- Dequeue : Retire l'élément à l'avant de la file.
De plus, nous pouvons ajouter deux opérations supplémentaires :
- Front : Renvoie la valeur de l'élément situé à l'avant de la file, sans le retirer.
- Rear : Renvoie la valeur de l'élément situé à l'arrière de la file, sans le retirer.
📝 Implementation
Pour mettre en œuvre une file, nous pouvons utiliser une structure liée. Dans cet exemple, nous utiliserons une liste chaînée. Voici une implémentation simple d'une file en utilisant une liste chaînée :
function initQueue() {
const queue = {
front: null,
rear: null,
count: 0,
};
return queue;
}
function enqueue(queue, item) {
const newNode = {
data: item,
next: null,
};
if (queue.rear === null) {
queue.front = newNode;
queue.rear = newNode;
} else {
queue.rear.next = newNode;
queue.rear = newNode;
}
queue.count++;
}
function dequeue(queue) {
if (queue.front === null) {
throw new Error('Queue is empty');
}
const item = queue.front.data;
queue.front = queue.front.next;
if (queue.front === null) {
queue.rear = null;
}
queue.count--;
return item;
}
function front(queue) {
if (queue.front === null) {
throw new Error('Queue is empty');
}
return queue.front.data;
}
function rear(queue) {
if (queue.rear === null) {
throw new Error('Queue is empty');
}
return queue.rear.data;
}
function isEmpty(queue) {
return queue.front === null;
}
function isFull(queue) {
return false; // In a linked implementation, the queue is never full
}
// Example usage:
const queue = initQueue();
enqueue(queue, 10);
enqueue(queue, 20);
enqueue(queue, 30);
console.log(front(queue)); // Output: 10
console.log(dequeue(queue)); // Output: 10
console.log(dequeue(queue)); // Output: 20
console.log(isEmpty(queue)); // Output: false
console.log(isFull(queue)); // Output: false
🔍 Comparing Stack and Queue
Maintenant que nous avons examiné les structures de données de la pile et de la file, vous vous demandez peut-être quand utiliser l'une ou l'autre. Voici quelques situations courantes dans lesquelles chaque structure est particulièrement utile :
🤔 When to Use Stack
- Reversing elements : Si vous avez besoin de traiter des éléments dans l'ordre inverse dans lequel ils ont été ajoutés, la pile est utile. Par exemple, pour inverser l'ordre des mots dans une phrase.
- Backtracking : Lors de la mise en œuvre d'un algorithme de recherche en profondeur, vous pouvez utiliser une pile pour stocker les états précédents et revenir en arrière si nécessaire.
- Expression evaluation : Lorsqu'il s'agit d'évaluer des expressions mathématiques, la pile est souvent utilisée pour gérer l'ordre d'évaluation des opérations.
- Memory management : Les piles sont utilisées dans la gestion de la mémoire pour stocker les adresses de retour des fonctions et les variables locales.
🤔 When to Use Queue
- Print queues : Lorsque plusieurs tâches d'impression doivent être exécutées en séquence, une file est utilisée pour stocker les demandes d'impression jusqu'à ce que l'imprimante puisse les traiter.
- Breadth-first search : Dans les algorithmes de recherche en largeur, une file est utilisée pour stocker les nœuds adjacents à visiter.
- Process scheduling : Les files sont utilisées dans les systèmes d'exploitation pour gérer l'ordre d'exécution des processus en attente.
- Request handling : Lors de la manipulation des demandes provenant de plusieurs utilisateurs, une file est utilisée pour traiter les demandes dans l'ordre d'arrivée.
En fonction de votre cas d'utilisation spécifique, vous pouvez choisir entre une pile et une file pour résoudre efficacement votre problème.
💻 Demo: Stack in Action
Voyons maintenant une démonstration pratique de l'utilisation d'une pile. Dans cet exemple, nous allons créer un programme pour vérifier si un mot est un palindrome.
❗ Example Program for Palindrome Checking
function isPalindrome(word) {
const stack = initStack();
for (let i = 0; i < word.length; i++) {
const letter = word[i];
push(stack, letter);
}
let reversedWord = '';
while (!isEmpty(stack)) {
reversedWord += pop(stack);
}
return word === reversedWord;
}
console.log("Is 'tuna' a palindrome?", isPalindrome('tuna')); // Output: false
console.log("Is 'radar' a palindrome?", isPalindrome('radar')); // Output: true
console.log("Is 'level' a palindrome?", isPalindrome('level')); // Output: true
console.log("Is 'hello' a palindrome?", isPalindrome('hello')); // Output: false
⌨️ Code Explanation
- Nous utilisons une pile pour inverser l'ordre des lettres du mot.
- En parcourant chaque lettre du mot, nous utilisons l'opération de push pour ajouter chaque lettre à la pile.
- Ensuite, nous utilisons l'opération de pop pour inverser l'ordre et reconstruire le mot inversé.
- Enfin, nous comparons le mot inversé avec le mot original pour déterminer s'ils sont identiques ou non, ce qui nous permet de vérifier si le mot est un palindrome ou non.
💻 Demo: Queue in Action
Continuons avec une autre démonstration pratique, cette fois en utilisant une file. Dans cet exemple, nous allons créer un programme pour simuler une file d'attente d'impression.
❗ Example Program for Print Queue
function printJobQueue() {
const queue = initQueue();
console.log('Print queue started.');
const printJob1 = 'Document 1';
enqueue(queue, printJob1);
console.log('Added', printJob1, 'to the print queue.');
const printJob2 = 'Document 2';
enqueue(queue, printJob2);
console.log('Added', printJob2, 'to the print queue.');
const printJob3 = 'Document 3';
enqueue(queue, printJob3);
console.log('Added', printJob3, 'to the print queue.');
while (!isEmpty(queue)) {
const currentJob = dequeue(queue);
console.log('Printing', currentJob);
}
console.log('Print queue finished.');
}
printJobQueue();
⌨️ Code Explanation
- Nous utilisons une file pour simuler une file d'attente d'impression.
- Nous ajoutons trois travaux d'impression à la file en utilisant l'opération enqueue.
- Ensuite, nous utilisons l'opération dequeue pour retirer chaque travail d'impression de la file et le traiter.
- Le résultat affiche l'ordre dans lequel les travaux d'impression sont traités, en respectant le principe FIFO.
👌 Conclusion
Félicitations ! Vous avez maintenant acquis une compréhension approfondie des structures de données de la pile et de la file, ainsi que de leur importance dans la programmation. Les piles et les files sont des outils puissants qui peuvent être utilisés pour résoudre une variété de problèmes, tels que l'inversion des éléments, la gestion des files d'attente et bien plus encore. En les utilisant de manière appropriée, vous serez en mesure d'améliorer l'efficacité de votre code et de résoudre des problèmes avec élégance. N'hésitez pas à expérimenter avec ces structures dans vos propres projets et à explorer d'autres structures de données pour étendre vos connaissances. Bonne programmation !