Structure de données - Pile
Une pile est une structure de données linéaire qui suit le principe du dernier entré, premier sorti (LIFO). Elle peut être comprise de manière imagée comme une pile d’assiettes — vous ne pouvez en poser une que sur le dessus, et vous ne pouvez en prendre une que sur le dessus.
Concept et principe de la pile
Vérification LIFO : push 10→20→30, pop 30→20→10 (dernier entré, premier sorti) | La pile ne se préoccupe que du sommet, pas du milieu
Implémentation par tableau (pile séquentielle)
Stockage : tableau de taille fixe + pointeur de sommet
push : items[++top] = value
pop : return items[top--]
Avantages : accès rapide, adapté au cache, implémentation simple
Inconvénients : capacité fixe, peut déborder
Implémentation par liste chaînée (pile chaînée)
Stockage : nœuds dynamiques + pointeur de sommet (tête de liste chaînée)
push : méthode d'insertion en tête newNode->next = top
pop : top = top->next; free(old head)
Avantages : aucune limite de capacité, extension dynamique flexible
Inconvénients : surcoût de pointeur supplémentaire, peu adapté au cache
Implémentation de pile par tableau
Exemple
#include <stdbool.h> /* type booléen */
#define MAX_SIZE 100 /* Capacité maximale de la pile */
/* Structure de pile : contient un tableau de données et un pointeur de sommet */
struct Stack {
int items[MAX_SIZE]; /* Tableau stockant les éléments de la pile */
int top; /* Pointeur de sommet, -1 signifie que la pile est vide */
};
/* Initialiser la pile : mettre top à -1 */
void initStack(struct Stack* s) {
s->top = -1;
}
/* Vérifier si vide : la pile est vide lorsque top vaut -1 */
bool isEmpty(struct Stack* s) {
return s->top == -1;
}
/* Vérifier si pleine : la pile est pleine lorsque top atteint la limite de capacité -1 */
bool isFull(struct Stack* s) {
return s->top == MAX_SIZE - 1;
}
/* Empiler : placer un élément au sommet de la pile
D'abord déplacer top, puis écrire les données */
void push(struct Stack* s, int value) {
if (isFull(s)) {
printf("La pile est pleine, impossible d'empiler !\n");
return;
}
s->items[++s->top] = value; /* top est d'abord incrémenté de 1, puis on affecte value */
printf("Empiler : %d\n", value);
}
/* Dépiler : retirer et renvoyer l'élément au sommet
D'abord récupérer les données, puis déplacer top */
int pop(struct Stack* s) {
if (isEmpty(s)) {
printf("La pile est vide, impossible de dépiler !"\n");
return -1; /* Retourne une valeur spéciale pour indiquer une erreur */
}
return s->items[s->top--]; /* Retourne d'abord la valeur, puis décrémente top */
}
/* Peek : ne dépile pas, consulte seulement le sommet */
int peek(struct Stack* s) {
if (isEmpty(s)) {
printf("La pile est vide !"\n");
return -1;
}
return s->items[s->top];
}
int main() {
struct Stack s;
initStack(&s);
push(&s, 10); /* Empiler : 10 */
push(&s, 20); /* Empiler : 20 */
push(&s, 30); /* Empiler : 30 */
printf("Élément au sommet : %d\n", peek(&s)); /* Sortie : élément au sommet : 30 */
printf("Dépiler : %d\n", pop(&s)); /* Sortie : dépiler : 30 (dernier entré, premier sorti) */
printf("Dépiler : %d\n", pop(&s)); /* Sortie : dépiler : 20 */
printf("Dépiler : %d\n", pop(&s)); /* Sortie : dépiler : 10 */
if (isEmpty(&s)) {
printf("La pile est vide\n"); /* Sortie : la pile est vide */
}
return 0;
}
Implémentation d'une pile par liste chaînée
Exemple
#include <stdlib.h>
#include <stdbool.h>
/* Nœud de liste chaînée */
struct Node {
int data;
struct Node* next;
};
/* Empiler : utilise la tête de la liste chaînée comme sommet de la pile, méthode d'insertion en tête
Complexité temporelle : O(1) */
struct Node* push(struct Node* top, int value) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode->next = top; /* Le nouveau nœud pointe vers le sommet original de la pile */
printf("Empiler : %d\n", value);
return newNode; /* Le nouveau nœud devient le nouveau sommet de la pile */
}
/* Dépiler : supprimer le nœud de tête de la liste chaînée
Complexité temporelle : O(1) */
struct Node* pop(struct Node* top) {
if (top == NULL) {
printf("La pile est vide !"\n");
return NULL;
}
struct Node* temp = top;
printf("Dépilé : %d\n", top->data);
top = top->next; /* Déplacer top vers l'arrière */
free(temp); /* Libérer l'ancien sommet */
return top;
}
/* Vérifier si vide */
bool isEmpty(struct Node* top) {
return top == NULL;
}
int main() {
struct Node* stackTop = NULL; /* Initialement, la pile est vide */
stackTop = push(stackTop, 100); /* Empiler : 100 */
stackTop = push(stackTop, 200); /* Empiler : 200 */
stackTop = push(stackTop, 300); /* Empiler : 300 */
printf("Sommet : %d\n", stackTop->data); /* Sortie : Sommet : 300 */
stackTop = pop(stackTop); /* Dépiler : 300 */
stackTop = pop(stackTop); /* Dépiler : 200 */
stackTop = pop(stackTop); /* Dépiler : 100 */
if (isEmpty(stackTop)) {
printf("La pile est vide\n"); /* Sortie : La pile est vide */
}
return 0;
}
L'avantage d'implémenter une pile avec une liste chaînée est que, théoriquement, il n'y a pas de limite de capacité fixe, limitée uniquement par la mémoire disponible du système. Cependant, chaque nœud nécessite un espace de stockage supplémentaire pour le pointeur.
Scénarios d'application des piles
| Scénarios d'application | Description | Pourquoi utiliser une pile |
|---|---|---|
| Pile d'appels de fonctions | Enregistrer les adresses de retour des fonctions et les variables locales | Les appels de fonctions sont imbriqués, naturellement LIFO |
| Appariement des parenthèses | Vérifier si les parenthèses dans le code sont correctement appariées | Empiler la parenthèse gauche sur la pile, dépiler la parenthèse droite lorsqu'elle correspond au sommet de la pile |
| Opération d'annulation | Fonction d'annulation dans les éditeurs de texte et les navigateurs | Chaque opération est empilée sur la pile, dépilée lors de l'annulation |
| Évaluation d'expressions | Évaluer des expressions infixes/postfixées | Les opérandes sont empilés sur la pile, le résultat est empilé après le calcul de l'opérateur |
| Recherche en profondeur d'abord | Algorithme de parcours DFS pour les graphes | Utiliser explicitement une pile ou la récursion (en utilisant implicitement la pile d'appels) |