Exercices sur les piles et les files d'attente de structure de données : conversion d'expressions arithmétiques en expressions postfixées (implémentation en langage C)

teneur

Introduction

2. Analyse du problème

3. Exemple d'application - les expressions d'arithmétique générale sont converties en expressions de suffixe

(1) Définition des fonctions de fonctionnement de base de la pile

(2) Fonction principale

(3) Résultat de l'opération

 (4), code complet

(5) Résumé


Introduction:

       Il a fallu une journée pour implémenter cette fonction avec du code. Le processus était très pénible, et il y avait beaucoup d'erreurs. Peut-être que j'étais relativement bon, et il a fallu une journée pour le déboguer. Comme le dit le proverbe : faire des erreurs est le début de l'amélioration de soi. S'il n'y a pas d'erreur, le problème ne sera jamais trouvé. Ce n'est qu'en apparaissant, en analysant et en résolvant le problème que vous pouvez gagner quelque chose et vous améliorer. Le processus est difficile, mais au moment où le problème est résolu, c'est comme gagner à la loterie Idem . La conversion d'expressions arithmétiques en expressions postfixées est une application classique des piles. L'idée est la même, maîtrisant cette idée, toutes les expressions arithmétiques peuvent être converties en expressions suffixes en utilisant cette idée, et le code est universel.

Merci d'indiquer le lien de cet article lors de la réimpression !

Deuxièmement, l'analyse du problème :

       Qu'est-ce qu'une expression arithmétique : c'est l'expression des problèmes mathématiques que nous réalisons habituellement, tels que : a*b+(cd/e)*f

       Qu'est-ce qu'une expression suffixe : placez l'opérateur après l'opérande, l'expression suffixe correspondant à la formule ci-dessus est : ab*cde/-f*+, l'opérateur devant est exécuté en premier. Sinon, l'ordre relatif des opérandes est inchangé et les parenthèses ne sont pas incluses dans les expressions postfixées.

        Nous devons analyser comment définir les conditions pour que l'ordinateur puisse comprendre nos pensées et ce que nous voulons que l'ordinateur fasse. Nous pouvons voir certaines choses d'un coup d'œil, mais l'ordinateur a besoin que nous lui transmettions des instructions avant de pouvoir nous suivre. .idées à travailler.

        Pour la pile, nous devons d'abord savoir que la pile est un tableau premier entré, dernier sorti, et que seules les opérations pop et push sont autorisées en haut de la pile. Les tableaux doivent avoir une taille, nous pouvons d'abord définir un tableau suffisamment grand pour stocker nos expressions arithmétiques d'entrée. Définissez ensuite une structure de pile, une pile S1 est utilisée pour stocker l'expression de suffixe finale, l'emplacement de la pile S1 est l'ordre inverse de l'expression de suffixe, nous pouvons utiliser un tableau pour obtenir les éléments de cette pile S1, lors de la sortie, à partir de Le dernier bit peut être sorti vers l'avant.Pourquoi utiliser la pile S1 pour stocker l'expression de suffixe au lieu du tableau?Parce que la pile est très pratique à utiliser, il vous suffit d'appeler des fonctions telles que faire apparaître la pile et pousser la pile.De Bien sûr, vous pouvez également utiliser une baie de stockage direct. Une autre pile S2 est utilisée pour stocker les opérateurs dans l'expression arithmétique, et l'opérateur qui fait apparaître la pile en premier exécute l'opération en premier ! Par conséquent, nous devons définir certaines conditions pour déterminer quand l'opérateur dans S2 est sorti de la pile et quand l'opérateur actuellement scanné est poussé sur la pile. 

        Analysez l'expression arithmétique actuelle pour obtenir le caractère C actuel : il existe les règles suivantes pour apparaître dans la pile :

(1) Si c='(' le crochet gauche, stockez-le directement dans la pile S2 de l'expression postfixée.

        //如果是左括号,直接进栈
        if(c=='(')
        {
            Push(&S2,c);
        }

(2) Si c=')' ferme la parenthèse, on obtient l'élément supérieur de la pile S2 de l'opérateur de stockage courant, s'il n'est pas égal à la parenthèse gauche '(', l'élément supérieur de la pile S2 est avancé à S1, puis S2 effectue l'opération de sortie, puis obtient à nouveau l'élément supérieur de la pile S2, continue d'effectuer l'étape (2) et exécute la boucle. Jusqu'à ce que la parenthèse gauche '(' soit rencontrée pour la première fois, la boucle est arrêtée et le '(' est supprimé de S2 Il suffit de le retirer de la pile et de continuer à parcourir le caractère suivant de l'expression arithmétique.

        else if(c==')')
        {
            char b=Get(S2);//获取存操作符的栈顶元素
            while(b!='(')//遇见左括号之前一直循环出栈S2
            {
                Push(&S1,b);//存入到栈S1
                Pop(&S2);    //进行出栈S2
                b=Get(S2);//再获取栈顶S2的元素
                //printf("--------++%c\n",b);
            }
            Pop(&S2);

(3) Si c!='+' et c!='-' et c!='*' et c!='/' et c!=')'. Ensuite, nous le stockons directement dans la pile S1 de l'expression postfixée. Ici, on peut comprendre que c est un nombre ou c est une série de variables inconnues x. Continuez à balayer le caractère suivant de l'expression arithmétique.

        else if(c!='+'&&c!='-'&&c!='*'&&c!='/'&&c!=')')//根据题目变换
        {
            Push(&S1,c);
        }

(4) Si c=='+' ou c=='-', c'est-à-dire que nous avons maintenant rencontré les deux opérateurs d'addition et de soustraction, nous jugeons d'abord si la pile S2 est une pile vide, si c'est une pile vide pile, alors nous pouvons mettre directement l'opérateur courant c dans la pile S2. S'il n'est pas vide, on obtient quel est l'élément supérieur de la pile S2. S'il s'agit d'un crochet gauche '(', alors nous pouvons mettre directement l'opérateur courant c dans la pile S2 ; si ce n'est pas un crochet gauche '(', alors nous allons d'abord empiler l'élément supérieur de la pile S2 dans S1, puis laissez S2 effectuer l'opération pop, puis obtenez à nouveau l'élément supérieur de la pile S2, et exécutez cette étape (4) dans une boucle, jusqu'à ce que la parenthèse gauche '(' soit rencontrée pour la première fois, ou que la pile soit vide, la boucle est arrêtée et le '(' suffit de sortir la pile de S2 et de continuer à parcourir le caractère suivant de l'expression arithmétique. Si le crochet gauche n'est pas rencontré, nous continuons à faire sauter la pile jusqu'à ce que la pile soit vide, puis poussez c dans la pile S2. Continuez à parcourir l'expression arithmétique du caractère suivant de la formule.

        else if(c=='+'||c=='-')
        {
            if(S2.top==-1)         //如果操作符栈为空,直接进栈
            {
                Push(&S2,c);
            }
            else
            {
                b=Get(S2);
                while(b!='(')         //只要不为左括号或者是栈不为空,那就一直出栈
                {
                    Push(&S1,b);         //运算符存入到栈S1中
                    Pop(&S2);
                    if(S2.top!=-1)            //栈不为空,执行一次出栈
                    {
                        b=Get(S2);           //再获取栈顶
                    }
                    else
                    {
                        break;
                    }
                }
                Push(&S2,c);
            }

        }

(5) Si c=='*'||c=='/', c'est-à-dire que nous avons rencontré les deux opérateurs de multiplication et de division, nous jugeons d'abord si la pile S2 est une pile vide, si c'est une pile vide pile, nous mettons simplement l'opérateur courant c dans la pile S2. S'il n'est pas vide, on obtient l'élément du haut de la pile S2, si b!='(' et b!='+' et b!='-', ici est utilisé et, non utilisé ou, i Voici un problème. Seulement quand ce n'est pas pour ces trois, c'est vrai en même temps. On pousse l'élément supérieur du courant S2 dans la pile S1, puis la pile S2 effectue l'opération de pop, puis obtient la pile du empiler à nouveau S2. L'élément supérieur, répétez (5), jusqu'à ce que la pile soit vide ou que l'élément supérieur de la pile soit égal à l'un des trois ci-dessus, nous arrêtons la boucle et mettons l'opérateur courant c dans la pile S2 . pour balayer l'expression arithmétique le caractère suivant.

    else if(c=='*'||c=='/')
        {
            if(S2.top==-1)
            {
               Push(&S2,c);
            }
            else
            {
                b=Get(S2);
                while(b!='('&&b!='+'&&b!='-')
                {
                    Push(&S1,b);          //运算符存入到栈S1中
                    Pop(&S2);
                    if(S2.top!=-1)             //执行一次出栈
                    {
                       b=Get(S2);
                    }
                    else
                    {
                        break;
                    }
                }
                Push(&S2,c);
            }
        }

(6) Lorsque le tableau d'expressions arithmétiques est parcouru, les opérateurs stockés dans la pile S2 sont extraits de la pile et entrés tour à tour dans la pile S1. À ce moment, l'ordre dans la pile S1 est l'ordre inverse de l'expression de suffixe que nous avons Nous stockons cet ordre inverse dans un tableau, et inverser la sortie de ce tableau est l'expression de suffixe dont nous avons besoin.

    while(S2.top!=-1)      //将S2中剩余的操作符存入到栈S1中
    {
        char c=Get(S2);
        Push(&S1,c);
        Pop(&S2);
    }
    int a=S1.top;           //记录后缀表达式的长度
    for(int i=0;S1.data[S1.top]!=-1;i++)   //将栈S1中的元素存入到数组中
    {
        data1[i]=S1.data[S1.top];
        S1.top--;
    }
    for(int i=a;i>=0;i--)             //反向输出数组即可
    {
        printf("%c",data1[i]);
    }

La figure suivante représente les étapes données dans le livre de Li Chunbao pour convertir des expressions arithmétiques en expressions suffixes : vous pouvez comprendre la mienne ou comprendre l'image suivante.

3. Exemple d'application - les expressions d'arithmétique générale sont converties en expressions de suffixe

La description

Pour une expression arithmétique basée sur un opérateur binaire, convertissez-la en l'expression postfixée correspondante et affichez-la.

Saisir

Entrez une expression arithmétique, terminée par le caractère '#'.

Production

Affiche l'expression postfixée obtenue en convertissant l'expression.

Échantillon

Saisir 

a*b+(cd/e)*f#

Production 

ab*cde/-f*+

(1) Définition des fonctions de fonctionnement de base de la pile

//定义一个栈结构体
typedef struct
{
    char data[Maxsize];    //存储元素
    int top;                //栈顶标记位
}Stack;
//初始化
void Init(Stack *L)
{
    L->top=-1;
}
//进栈操作
void Push(Stack *L,char x)
{
    if(L->top>=Maxsize)//判断是否栈满
    {
        return;
    }
    L->top++;
    L->data[L->top]=x;      //栈没满就将x入栈
}
//出栈操作
void Pop(Stack *L)
{
    if(L->top==-1)//判断是否为空
    {
        return;
    }
    L->top--;        //不空就将栈顶标记位减一
}
//获取栈顶元素
char Get(Stack L)
{
    if(L.top==-1)
    {
        return 0;
    }
    else
    {
        return L.data[L.top];
    }
}

(2) Fonction principale

La signification du bloc de code dans la fonction principale a été présentée en détail dans la deuxième partie de l'analyse du problème. Vous pouvez rassembler ce code pour comprendre ces mots, et la logique est très simple.

int main()
{
    Stack S1;//存放最终的表达式
    Stack S2;//存放运算符
    Init(&S1);
    Init(&S2);
    char data[Maxsize];//存放用户输入的表达式
    scanf("%s",data);
    char data1[Maxsize];
    char b;
    for(int i=0;data[i]!='#';i++)
    {
        char c=data[i];
        if(c=='(')
        {
            Push(&S2,c);
        }
        else if(c==')')
        {
            char b=Get(S2);//获取存操作符的栈顶元素
            while(b!='(')//遇见左括号之前一直循环出栈S2
            {
                Push(&S1,b);//存入到栈S1
                Pop(&S2);    //进行出栈S2
                b=Get(S2);//再获取栈顶S2的元素
            }
            Pop(&S2);
        }
        else if(c!='+'&&c!='-'&&c!='*'&&c!='/'&&c!=')')//根据题目变换
        {
            Push(&S1,c);
        }
        else if(c=='+'||c=='-')
        {
            if(S2.top==-1)         //如果操作符栈为空,直接进栈
            {
                Push(&S2,c);
            }
            else
            {
                b=Get(S2);
                while(b!='(')         //只要不为左括号或者是栈不为空,那就一直出栈
                {
                    Push(&S1,b);         //运算符存入到栈S1中
                    Pop(&S2);
                    if(S2.top!=-1)            //栈不为空,执行一次出栈
                    {
                        b=Get(S2);           //再获取栈顶
                    }
                    else
                    {
                        break;
                    }
                }
                Push(&S2,c);
            }

        }
        else if(c=='*'||c=='/')
        {
            if(S2.top==-1)
            {
               Push(&S2,c);
            }
            else
            {
                b=Get(S2);
                while(b!='('&&b!='+'&&b!='-')
                {
                    Push(&S1,b);          //运算符存入到栈S1中
                    Pop(&S2);
                    if(S2.top!=-1)             //执行一次出栈
                    {
                       b=Get(S2);
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
    }
    while(S2.top!=-1)
    {
        char c=Get(S2);
        Push(&S1,c);
        Pop(&S2);
    }
    int a=S1.top;
    for(int i=0;S1.data[S1.top]!=-1;i++)
    {
        data1[i]=S1.data[S1.top];
        S1.top--;
    }
    for(int i=a;i>=0;i--)
    {
        printf("%c",data1[i]);
    }
    return 0;
}

(3) Résultat de l'opération

 (4), code complet

#include <stdio.h>
#include <stdlib.h>
#define Maxsize 1000
//定义一个栈结构体
typedef struct
{
    char data[Maxsize];    //存储元素
    int top;                //栈顶标记位
}Stack;
//初始化
void Init(Stack *L)
{
    L->top=-1;
}
//进栈操作
void Push(Stack *L,char x)
{
    if(L->top>=Maxsize)//判断是否栈满
    {
        return;
    }
    L->top++;
    L->data[L->top]=x;      //栈没满就将x入栈
}
//出栈操作
void Pop(Stack *L)
{
    if(L->top==-1)//判断是否为空
    {
        return;
    }
    L->top--;        //不空就将栈顶标记位减一
}
//获取栈顶元素
char Get(Stack L)
{
    if(L.top==-1)
    {
        return 0;
    }
    else
    {
        return L.data[L.top];
    }
}
int main()
{
    Stack S1;//存放最终的表达式
    Stack S2;//存放运算符
    Init(&S1);
    Init(&S2);
    char data[Maxsize];//存放用户输入的表达式
    scanf("%s",data);
    char data1[Maxsize];
    char b;
    for(int i=0;data[i]!='#';i++)
    {
        char c=data[i];
        if(c=='(')
        {
            Push(&S2,c);
        }
        else if(c==')')
        {
            char b=Get(S2);//获取存操作符的栈顶元素
            while(b!='(')//遇见左括号之前一直循环出栈S2
            {
                Push(&S1,b);//存入到栈S1
                Pop(&S2);    //进行出栈S2
                b=Get(S2);//再获取栈顶S2的元素
            }
            Pop(&S2);
        }
        else if(c!='+'&&c!='-'&&c!='*'&&c!='/'&&c!=')')//根据题目变换
        {
            Push(&S1,c);
        }
        else if(c=='+'||c=='-')
        {
            if(S2.top==-1)         //如果操作符栈为空,直接进栈
            {
                Push(&S2,c);
            }
            else
            {
                b=Get(S2);
                while(b!='(')         //只要不为左括号或者是栈不为空,那就一直出栈
                {
                    Push(&S1,b);         //运算符存入到栈S1中
                    Pop(&S2);
                    if(S2.top!=-1)            //栈不为空,执行一次出栈
                    {
                        b=Get(S2);           //再获取栈顶
                    }
                    else
                    {
                        break;
                    }
                }
                Push(&S2,c);
            }

        }
        else if(c=='*'||c=='/')
        {
            if(S2.top==-1)
            {
               Push(&S2,c);
            }
            else
            {
                b=Get(S2);
                while(b!='('&&b!='+'&&b!='-')
                {
                    Push(&S1,b);          //运算符存入到栈S1中
                    Pop(&S2);
                    if(S2.top!=-1)             //执行一次出栈
                    {
                       b=Get(S2);
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
    }
    while(S2.top!=-1)
    {
        char c=Get(S2);
        Push(&S1,c);
        Pop(&S2);
    }
    int a=S1.top;
    for(int i=0;S1.data[S1.top]!=-1;i++)
    {
        data1[i]=S1.data[S1.top];
        S1.top--;
    }
    for(int i=a;i>=0;i--)
    {
        printf("%c",data1[i]);
    }
    return 0;
}

(5) Résumé

        Cette question m'a pris une journée. Je l'ai vraiment déboguée petit à petit. J'ai ajouté une instruction d'impression à chaque condition pour voir quelle condition s'est mal passée, et j'ai finalement déterminé que le problème s'était produit dans When c=* or c=/ this jugement, when en scannant ceci, nous devrions définir cette condition b!='('&&b!='+'&&b!='-', pas b!='( '||b!='+'||b!='- ', car && signifie que tout vrai est vrai, et || signifie que tant qu'un est vrai, il est vrai, et les conditions de la condition seront exécutées. Corps de la boucle. Par exemple, prenons un exemple : a+( b*c+d)#, lorsque nous balayons vers la parenthèse fermante), si nous utilisons b!='('||b!='+'|| La condition de b!='-', lorsque nous balayons vers le signe *, nous atteignons la parenthèse gauche b=( en haut de la pile d'opérateurs, puis nous utilisons b!='('||b!='+'| Quand |b!='-' est utilisé comme condition, cette condition est vraie, car b n'est pas égal à +, - à ce moment. Ainsi, le contenu à l'intérieur sera exécuté. Mais ce que nous voulons exprimer, c'est quand b=(, nous poussons directement * sur la pile, pas pop ce.

        Bien que j'ai posé cette question aujourd'hui, cela m'a vraiment fait travailler dur et gagner quelque chose. Lors de la définition des conditions de jugement, nous devons considérer à la fois les côtés positifs et négatifs. Ce n'est que lorsque les conditions sont définies correctement que notre programme peut être exécuté conformément à ce que nous voulons c'est la direction à exécuter. allez!

Je suppose que tu aimes

Origine blog.csdn.net/BaoITcore/article/details/121456313
conseillé
Classement