Structures de données - Analyse d'expressions
L'analyse d'expressions est le scénario d'application le plus classique de la structure de données pile.
L'analyse d'expressions montre comment utiliser les piles pour gérer les conversions entre expressions infixes, préfixes et postfixes, ainsi que l'évaluation d'expressions.
Trois formes d'expressions
Lors du traitement d'expressions mathématiques dans un ordinateur, il existe trois méthodes de représentation :
| Type | Position de l'opérateur | Exemple | Difficulté d'évaluation | Exigence de parenthèses |
|---|---|---|---|---|
| Expression infixe | Entre les opérandes (convention humaine) | A + B * C | Nécessité de gérer la priorité et les parenthèses | Nécessaire |
| Expression préfixe(notation polonaise) | Avant les opérandes | + A * B C | Un seul balayage suffit | Non nécessaire |
| Expression postfixée(notation polonaise inverse) | Après les opérandes | A B C * + | Un seul balayage suffit | Non nécessaire |
Le plus grand avantage des expressions postfixées et préfixées est que, lors de l’évaluation, il n’est pas nécessaire de tenir compte de la priorité des opérateurs ni des parenthèses ; il suffit de parcourir séquentiellement de gauche à droite.
Algorithme de conversion d’infixe en postfixe (idée de l’algorithme Shunting Yard)
L’algorithme central pour convertir une expression infixe en expression postfixée est mis en œuvre à l’aide d’une pile. Le processus de base est le suivant :
- Parcourir l’expression infixe de gauche à droite
- Lorsqu’on rencontreun opérande(chiffre/lettre), l’afficher directement
- Lorsqu’on rencontreun opérateur, comparer sa priorité avec celle de l’opérateur au sommet de la pile :
- Si l’opérateur au sommet de la pile a une priorité supérieure ou égale, dépiler le sommet et l’afficher
- Répéter ce processus jusqu’à ce que l’opérateur courant puisse être empilé
- Lorsqu’on rencontreune parenthèse ouvrante, l’empiler directement
- Lorsqu'on rencontreune parenthèse fermante, continuer à dépiler les opérateurs du sommet de la pile et à les afficher jusqu'à ce qu'une parenthèse ouvrante soit rencontrée (la parenthèse ouvrante est dépilée mais n'est pas affichée)
- Une fois l'analyse terminée, dépiler et afficher un par un les opérateurs restants dans la pile
Exemple
#include <ctype.h> /* fonction isalnum */
#include <string.h>
#define MAX 100
char stack[MAX];
int top = -1;
void push(char c) { stack[++top] = c; }
char pop() { return (top == -1) ? -1 : stack[top--]; }
/* Renvoie la priorité de l'opérateur : un nombre plus élevé signifie une priorité plus élevée */
int precedence(char op) {
if (op == '+' || op == '-') return 1; /* L'addition et la soustraction ont la priorité la plus faible */
if (op == '*' || op == '/') return 2; /* La multiplication et la division ont une priorité plus élevée */
if (op == '^') return 3; /* L'exponentiation a la plus haute priorité */
return 0; /* Pas un opérateur */
}
Expression infixe vers expression postfixe
Paramètres : infix - la chaîne d'expression infixe d'entrée
postfix - le tampon d'expression postfixe de sortie */
void infixToPostfix(char* infix, char* postfix) {
int i = 0, j = 0;
char c;
while ((c = infix[i++]) != '\0') {
/* Opérande (lettre ou chiffre) : sortie directe */
if (isalnum(c)) {
postfix[j++] = c;
}
/* Parenthèse gauche : empiler directement */
else if (c == '(') {
push(c);
}
/* Parenthèse fermante : dépiler jusqu'à ce qu'une parenthèse ouvrante soit rencontrée */
else if (c == ')') {
while (top != -1 && stack[top] != '(') {
postfix[j++] = pop();
}
pop(); /* Dépiler la parenthèse ouvrante '(' mais ne pas l'afficher */
}
/* Opérateur : gérer la priorité */
else {
while (top != -1 &&
precedence(stack[top]) >= precedence(c) &&
stack[top] != '(') {
postfix[j++] = pop();
}
push(c);
}
}
/* Dépiler tous les opérateurs restants de la pile */
while (top != -1) {
postfix[j++] = pop();
}
postfix[j] = '\0'; /* Fin de la chaîne */
}
int main() {
char infix[] = "A+B*C";
char postfix[MAX];
infixToPostfix(infix, postfix);
printf("میانوند: %s\n", infix); /* خروجی: میانوند: %s */
printf("پستفیکس: %s\n", postfix); /* خروجی: پستفیکس: %s */
return 0;
}
ارزیابی عبارت پستفیکس
Avec l'expression postfixe, l'évaluation à l'aide d'une pile est très simple : empiler les opérandes sur la pile ; lorsqu'on rencontre un opérateur, dépiler deux opérandes, calculer, et empiler le résultat.
Exemple
#include <ctype.h>
#include <stdlib.h>
#define MAX 100
int stack[MAX];
int top = -1;
void push(int val) { stack[++top] = val; }
int pop() { return stack[top--]; }
/* Calculer la valeur de l'expression postfixe
Paramètres : postfix - expression postfixe (les opérandes sont des chiffres uniques 0-9)
Valeur de retour : le résultat calculé de l'expression */
int evaluatePostfix(char* postfix) {
int i = 0;
char c;
while ((c = postfix[i++]) != '\0') {
/* Opérande : convertir en nombre et empiler sur la pile */
if (isdigit(c)) {
push(c - '0'); /* '3' converti en entier 3 */
}
/* Opérateur : dépiler deux opérandes, effectuer le calcul, puis empiler à nouveau */
else {
int b = pop(); /* Deuxième opérande (opérande de droite) */
int a = pop(); /* Premier opérande (opérande de gauche) */
switch (c) {
case '+': push(a + b); break;
case '-': push(a - b); break;
case '*': push(a * b); break;
case '/': push(a / b); break;
}
}
}
return pop(); /* Le dernier élément de la pile est le résultat final */
}
int main() {
/* L'expression postfixée "23+5*" est équivalente à l'expression infixe "(2+3)*5" = 25 */
char postfix[] = "23+5*";
int result = evaluatePostfix(postfix);
printf("Postfixe %s = %d\n", postfix, result); /* Sortie : Postfixe 23+5* = 25 */
return 0;
}
Lors de l'évaluation d'une expression postfixée, l'ordre de dépilement des opérandes est crucial : le premier dépilé estopérande droit(b), et celui dépilé ensuite estopérande gauche(a). Cela est particulièrement important pour les opérations non commutatives comme la soustraction et la division ; inverser l'ordre produira des résultats incorrects.
Exemple complet : Évaluation d'expression infixe
En enchaînant les deux étapes ci-dessus, on obtient une calculatrice complète : infixe → postfixe → évaluation.
Exemple
#include <ctype.h>
#define MAX 100
/* Fonction auxiliaire de priorité des opérateurs (comme ci-dessus), fonction d'évaluation (comme ci-dessus), fonction de conversion (comme ci-dessus) */
/* Par souci de concision, les fonctions définies ci-dessus sont omises ici ; incluez-les lors de l'utilisation réelle */
int main() {
char infix[] = "5+3*2"; /* Expression infixe */
char postfix[MAX];
infixToPostfix(infix, postfix); /* Étape 1 : Convertir en postfixe */
printf("Infixe : %s\n", infix); /* Sortie : Infixe : 5+3*2 */
printf("Postfixe : %s\n", postfix); /* Sortie : Postfixe : 532*+ */
int result = evaluatePostfix(postfix); /* Étape 2 : Évaluer */
printf("Résultat : %s = %d\n", infix, result);
/* Sortie : Résultat : 5+3*2 = 11 */
return 0;
}