[Structure de données] Application de la pile C++ : calculatrice d'expression polonaise, polonaise inversée et infixe

 ****************************************************** ****************************************************** *****

L'auteur de cet article est Noah Lazy Yangyang, un camarade de classe de MF22, HKUST, pour vous donner une idée de devoir, merci de ne pas copier directement ! ! ! Apprenons ensemble~

****************************************************** ****************************************************** ******

Table des matières

1. Description du problème

1.1 Fonctions de base

1.2 Robustesse

1.3 Normatif

2. Description de l'algorithme

2.1 Description de la structure des données

2.2 Description de la structure du programme

3. Analyse de débogage

4. Analyse spatio-temporelle de l'algorithme

5. Résultats des tests et analyse

annexe du code

Noah_stack.h

Noah_Cal_Expression_With_Stack.h

Noah_expression_noemaltoRPN.h

Main.cpp


1. Description du problème

1.1 Fonctions de base

1. Calcul polonais

+ 2 * 3 - 5 1 = 2 + 3 * (5 - 1) = 14 (11 points)

+ + 2 * 3 - 7 4 / 8 4=2+3*(7-4)+8/4=13(12 points)

2. Calcul polonais inversé

2 3 5 1 - * += 2 + 3 * (5 - 1)=14 (11 points)

9 3 1 – 3* + 10 2 / +=9+(3-1)*3+10/2=20(12 points)

                        

3. Calcul de l'infixe

(1) résultat du calcul 4 + 2 * 3 – 10 / 5, devrait produire 8 (12 points);

(2)(4+2)*3 – 10 / 5 Le résultat du calcul devrait donner 16 (12 points) ;

1.2 Robustesse

  1. Le programme a une certaine gestion des exceptions, telles que les entrées illégales, etc.

Par exemple:

L'expression d'entrée contient des caractères illégaux, (2 points)

Par exemple : + 2 A, 2 3 A -, 4 + a

  1. Le nombre d'opérandes et d'opérateurs dans l'expression d'entrée ne correspond pas (plus d'opérandes ou plus d'opérateurs) (4 points)

Tels que : + 2 2 2 , 2 2 2 + , 2 + 2 2 , + + 2 2 , 2 2 + +, 2 + + 2

  1. Une entrée illégale telle que l'appariement ne peut pas être complétée en saisissant des parenthèses d'expression. (4 points)

Comme (4 + 2 * 3, 4 + 2) * 3.

1.3 Normatif

  1. commentaire de code
  2. modularisation du programme
  3. Interaction amicale entre l'homme et l'ordinateur

2. Description de l'algorithme

2.1 Description de la structure des données

La structure de données principale utilisée dans le programme est la pile séquentielle.

 

Explication des principales variables :

variable

taper

illustrer

sq_stack

structure

La structure de la pile

*base

Le pointeur vers l'élément inférieur de la pile

Permet d'accéder à l'élément du bas de la pile, de contrôler le stockage de la pile, de calculer le nombre d'éléments dans la station, etc.

*haut

pointeur vers l'élément supérieur de la pile

Permet d'accéder à l'élément supérieur de la pile, de contrôler le stockage de la pile, de calculer le nombre d'éléments dans la station, etc.

taille de la pile

entier

La taille de l'espace mémoire de la pile séquentielle (le nombre d'éléments pouvant être stockés)

expression

chaîne

doit évaluer l'expression

STACK_INIT_SIZE

macro définition

Initialiser la taille de l'espace de stockage

STACK_INCREMENT_SIZE

macro définition

Taille d'incrément d'allocation de stockage

STK_Type d'élément

macro définition

Le type de données des éléments de la pile

2.2 Description de la structure du programme

        Le programme comprend principalement Noah_stack.h, Noah_expression_normaltoRPN.h, le fichier d'en-tête Noah_Cal_Expression_With_Stack.h et le fichier principal main.cpp, où Noah_stack.h est le fichier d'en-tête de code d'implémentation de la structure de données de la pile, et Noah_expression_normaltoRPN.h doit convertir l'expression infixe au fichier d'en-tête de collection de code de formule (polonais inversé) d'expression de suffixe, Noah_Cal_Expression_With_Stack.h est le fichier d'en-tête de collection de code de la fonction de calcul de différentes expressions réalisées par la structure de données de la pile d'appels et le code de conversion d'expression, main.cpp implémente principalement le menu et interface de fonction Interaction et appels aux fonctions dans les fichiers d'en-tête. Sa structure spécifique est illustrée dans la figure ci-dessous.

 

3. Analyse de débogage

Fonction de débogage 1 : calculateur d'expression polonaise

Évaluer les expressions polonaises

 

Sélection des données de test :

  1. + 2 * 3 - 5 1 = 2 + 3 * (5 - 1) = 14 (11 points)
  2. + + 2 * 3 - 7 4 / 8 4=2+3*(7-4)+8/4=13(12 points)

Problèmes et solutions :

  1. Étant donné que l'entrée io obtient un type de données de chaîne, il est nécessaire de reconnaître les symboles et les nombres, mais lors de la reconnaissance de nombres avec des dizaines ou des chiffres supérieurs, ils ne sont pas reconnus comme un nombre au début, mais sont reconnus comme des nombres multiples. , la solution est d'ajouter le code de contrôle de jugement correspondant pour résoudre ce problème.

Fonction de débogage deux : calculatrice d'expression polonaise inverse

Calcule l'expression polonaise inverse

 

Sélection des données de test :

  1. 2 3 5 1 - * += 2 + 3 * (5 - 1)=14 (11 points)
  2. 9 3 1 – 3 * + 10 2 / +=9+(3-1)*3+10/2=20(12 points)

Problèmes et solutions :

  1. Le code au début ne distinguait pas si "10" est un nombre 1, un nombre 0 ou un nombre 10. Pour résoudre ce problème, un espace doit être ajouté entre chaque nombre et l'opérateur lors de la restriction de l'entrée.

Fonction de débogage trois : calculatrice d'expression infixe

Évaluer les expressions infixes

 

Sélection des données de test :

  1. 4 + 2 * 3 – 10/5 résultat du calcul, devrait sortir 8 (12 points) ;
  2. (4+2)*3 – 10/5 résultat du calcul, devrait produire 16 (12 points) ;

Problèmes et solutions :

aucun

Fonction de débogage quatre : test de robustesse

 

Sélection des données de test :

  1. 1 + ( 5 * 6 – 10
  2. un , un + 5
  3. 2 3 A –
  4. + + 2 2
  5. 4 + 2)* 3

Problèmes et solutions :

aucun

4. Analyse spatio-temporelle de l'algorithme

(1)STK_Elemtype Polish_type_calculate(expression de chaîne)

Complexité temporelle : O(n)

Complexité spatiale : O(n)

(2) STK_Elemtype Inverse_Polish_type_calculate (expression de chaîne)

Complexité temporelle : O(n)

Complexité spatiale : O(n)

(3)STK_Elemtype Normal_type_calculate(expression de chaîne)

Complexité temporelle : O(n)

Complexité spatiale : O(n)

5. Résultats des tests et analyse

Fonction de test 1 : calculateur d'expression polonaise

cas de test

résultat

analyser

+ 2 * 3 - 5 1

 

√, le calcul polonais est correct

+ + 2 * 3 - 7 4 / 8 4

 

Fonction de débogage deux : calculatrice d'expression polonaise inverse

cas de test

résultat

analyser

2 3 5 1 - * +

 

√, la formule polonaise inverse est calculée correctement

9 3 1 – 3 * + 10 2 / +

 

Fonction de test trois : calculatrice d'expression infixe

cas de test

résultat

analyser

4 + 2 * 3 – 10 / 5

 

√, l'expression infixe est calculée correctement

( 4 + 2) * 3 – 10 / 5

 

Fonction de débogage quatre : test de robustesse

cas de test

résultat

analyser

1 + ( 5 * 6 – 10

 

un , un + 5

 

2 3 A –

 

4 + 2) * 3

 

+ + 2 2

 

annexe du code

Noah_stack.h

#ifndef NOAH_STACK_H_INCLUDED
#define NOAH_STACK_H_INCLUDED
#include <stdlib.h>
#define STACK_INIT_SIZE 100//初始化存储空间大小
#define STACK_INCREMENT_SIZE 10//存储空间分配增量大小
#define STK_Elemtype float
typedef struct{
    STK_Elemtype *base;
    STK_Elemtype *top;
    int stack_size;
}sq_stack;

//初始化栈(顺序栈)
void initStack(sq_stack &s){
    s.base = (STK_Elemtype *)malloc(STACK_INIT_SIZE * sizeof(STK_Elemtype));
    /*
    if(!s.base)
        exit(overflow_error);//内存空间不足初始化失败,程序退出
    */
    s.top = s.base;
    s.stack_size = STACK_INIT_SIZE;
}
//为顺序栈重新分配空间并将空间扩大incrementsize*sizeof(element)
void incrementStack(sq_stack &s,int incrementsize){
    s.base =(STK_Elemtype *)realloc(s.base,(s.stack_size + incrementsize)*sizeof(STK_Elemtype));
    /*
    if(!s.base)
        exit(overflow_error);//内存空间不足,增加size失败,程序退出
    */
    s.top = s.base + s.stack_size;
    s.stack_size += incrementsize;
}
//判断链表是否为空
int isStackempty(sq_stack s){
    if(s.base==s.top)
        return 1;//空
    else
        return 0;//非空
}
//判断链表是否存满
int isStackfull(sq_stack s){
    if(s.top - s.base >=s.stack_size)
        return 1;//存满
    else
        return 0;//没有存满
}
//取栈顶元素
STK_Elemtype GetTop(sq_stack s){
    //首先判断元素是否为空
    if(isStackempty(s)){
        cout << "The stack is Empty, return -1." << endl;
        return STK_Elemtype(-1);
    }
    else
        return *(s.top - 1);
}

//入栈
void push(sq_stack &s,STK_Elemtype e){
    if(isStackfull(s))
        incrementStack(s,STACK_INCREMENT_SIZE);
    *s.top++ = e;
}

//出栈
STK_Elemtype pop(sq_stack &s){
    if(isStackempty(s)){
        cout << "The stack is Empty, return -1." << endl;
        return STK_Elemtype(-1);
    }
    else
        //cout<<"pop:"<<*(s.top-1);
        return *--s.top;

}
//返回链表中的元素个数
int len_Stack(sq_stack s){
    return s.top-s.base;
}

//打印链表中所有元素
void Display_Stack(sq_stack s){
    if(isStackempty(s)){
        printf("The stack is Empty.");
        return ;
    }
    for(int i = 0 ; i<len_Stack(s);i++)
        printf("%.2f    ",*(s.base+i));
}
#endif // NOAH_STACK_H_INCLUDED

Noah_Cal_Expression_With_Stack.h

#ifndef NOAH_CAL_EXPRESSION_WITH_STACK_H_INCLUDED
#define NOAH_CAL_EXPRESSION_WITH_STACK_H_INCLUDED
#include "Noah_stack.h"
#include "Noah_expression_normaltoRPN.h"
#include <string>
#include <sstream>
#include <cmath>
#include <iostream>
using namespace std;

string input_expression();
int check_expression(string expression);
STK_Elemtype Polish_type_calculate(string expression);
STK_Elemtype Inverse_Polish_type_calculate(string expression);
STK_Elemtype Normal_type_calculate(string expression);



//输入一个表达式
string input_expression(){
    int legal = 0;
    char expression_chars[256];
    string expression;
    while(!legal){
        cout <<"Please input the expression:"<<endl;
        cin.ignore();
        cin.getline(expression_chars,256);
        expression = expression_chars;
        legal = check_expression(expression);
        if(!legal){
            cout<<"Expression illegal, please input again."<<endl;
            //char expression_chars[256] = "";
        }
    }
    return expression;
}
//判断表达式是否合法,合法返回1,不合法返回0
int check_expression(string expression){
    //三种不合法的方式
    int expression_error_illegal_char = 0;
    int expression_error_unaligment_numberandoperation = 0;
    int expression_error_unaligment_bracket = 0;
    //中间控制变量
    int operands_num = 0;
    int operation_num = 0;
    int bracket_left = 0;
    int bracket_right = 0;
    string temp = "";
    //按字符判断,循环
    for (decltype(expression.size()) index = 0; index != expression.size(); index++){
        char x = expression[index];
        //cout<<x<<endl;
        if(temp.size()>0 && x==' '){
            temp = "";
            operands_num++;
        }
        if(x=='('||x==')'||x==' '){
            if(x=='(')
                bracket_left++;
            else if(x == ')')
                bracket_right++;
            continue;
        }
        if(x=='+'||x=='-'||x=='*'||x=='/'||x=='%'||x=='^')
            operation_num++;
        else if(x>='0'&&x<='9'){
            temp +=x;
            if(index == expression.size()-1)
                operands_num++;
        }
        else
            expression_error_illegal_char = 1;//有非法字符
        //cout<<x<<operands_num<<operation_num<<bracket_left<<bracket_right<<endl;
    }
    if(operands_num!=(operation_num+1))
        expression_error_unaligment_numberandoperation = 1;
    if(bracket_left!=bracket_right)
        expression_error_unaligment_bracket = 1;

    //检查结果输出
    if(expression_error_illegal_char||expression_error_unaligment_bracket||expression_error_unaligment_numberandoperation){
        cout<<expression<<" "<<"is illegal!"<<endl;
        if(expression_error_illegal_char)
            cout<<"The input expression has an invalid character."<<endl;
        if(expression_error_unaligment_numberandoperation)
            cout<<"The input expression operands do not match the number of operators."<<endl;
        if(expression_error_unaligment_bracket)
            cout<<"The expression brackets are not as paired."<<endl;
        return 0;//expression非法
    }
    return 1;//expression合法
}
//计算波兰式
STK_Elemtype Polish_type_calculate(string expression){
    sq_stack s;
    initStack(s);
    //逆序遍历表达式字符串
    string temp = "";
    for (decltype(expression.size()) index = expression.size()-1; index != -1; index--){
        char x = expression[index];
        if(temp.size()>0 && x==' '){
            push(s,stof(temp));
            temp = "";
        }
        /*
        cout<<x<<"  "<<"stack:";
        Display_Stack(s);
        cout<<endl;
        */
        if(x=='+'||x=='-'||x=='*'||x=='/'||x=='%'||x=='^'){
            switch(x){
            case('+'):
                push(s,pop(s)+pop(s));break;
            case('-'):
                push(s,(-pop(s)+pop(s)));break;
            case('*'):
                push(s,pop(s)*pop(s));break;
            case('/'):
                push(s,pop(s)/pop(s));break;
            case('%'):
                {
                    int temp1 = int(pop(s));
                    int temp2 = int(pop(s));
                    push(s,temp1%temp2);break;
                }
            case('^'):
                {
                    float temp1 = pop(s);
                    float temp2 = pop(s);
                    push(s,pow(temp1,temp2));break;
                }
            }
        }
        else if(x>='0'&&x<='9'){
            temp = x + temp;
            if(index==0)
                push(s,stof(temp));
        }
    }
    return pop(s);
}

//计算逆波兰式
STK_Elemtype Inverse_Polish_type_calculate(string expression){
    sq_stack s;
    initStack(s);
    //正序遍历表达式字符串
    string temp = "";
    for (decltype(expression.size()) index = 0; index != expression.size(); index++){
        char x = expression[index];
        if(temp.size()>0 && x==' '){
            push(s,stof(temp));
            temp = "";
        }
        /*
        cout<<x<<"  "<<"stack:";
        Display_Stack(s);
        cout<<endl;
        */
        if(x=='+'||x=='-'||x=='*'||x=='/'||x=='%'||x=='^'){
            switch(x){
            case('+'):
                push(s,pop(s)+pop(s));break;
            case('-'):
                push(s,(0-pop(s)+pop(s)));break;
            case('*'):
                push(s,pop(s)*pop(s));break;
            case('/'):
                push(s,1/pop(s)*pop(s));break;
            case('%'):
                {
                    int temp1 = int(pop(s));
                    int temp2 = int(pop(s));
                    push(s,temp2%temp1);break;
                }
            case('^'):
                {
                    float temp1 = pop(s);
                    float temp2 = pop(s);
                    push(s,pow(temp2,temp1));break;
                }
            }
        }
        else if(x>='0'&&x<='9'){
            temp = temp + x;
            if(index==expression.size()-1)
                push(s,stof(temp));
        }
    }
    return pop(s);
}

//计算中缀表达式,先转为逆波兰式再计算逆波兰式
STK_Elemtype Normal_type_calculate(string expression){
    return Inverse_Polish_type_calculate(RPN(expression));
}

#endif // NOAH_CAL_EXPRESSION_WITH_STACK_H_INCLUDED

Noah_expression_noemaltoRPN.h

#ifndef NOAH_EXPRESSION_NORMALTORPN_H_INCLUDED
#define NOAH_EXPRESSION_NORMALTORPN_H_INCLUDED
#include <iostream>
#include <cstring>
#include <stack>
#include "Noah_stack.h"

using namespace std;
int priority_func(char op);

//判断运算符的优先级
int priority_func(char op)
{
    int priority;
    if(op == '*' || op == '/') priority = 2;
    if(op == '+' || op == '-') priority = 1;
    if(op == '(') priority = 0;
    return priority;
}

//将中缀表达式转为逆波兰式
string RPN(string str)
{
    string str1="";
    stack<char> s;
    int i;
    string temp = "";
    for(i = 0; i < str.size(); i ++ )
    {
        //cout<<str[i]<<endl;
        if(str[i]==' '){
            //cout<<temp<<endl;
            if(temp.size()>0){
                str1 = str1+ " " + temp;
                temp = "";
            }
            continue;
        }
        //是数字的情况下直接输出
        if(str[i] >= '0' && str[i] <= '9' )
        {
            temp = temp+string(1,str[i]);
            if(i==str.size()-1)
                str1 = str1+ " " + temp;
        }
        else //不是数字的情况分类讨论进行判断
        {
            //栈为空时直接入栈
            if(s.empty()) s.push(str[i]);
            //左括号入栈
            else if(str[i] == '(') s.push(str[i]);
            //如果是右括号,只要栈顶不是左括号,就弹出并输出
            else if(str[i] == ')')
            {
                while(s.top() != '(')
                {
                    str1 = str1+ " " + s.top();
                    s.pop();
                }
                //弹出左括号,但不输出
                s.pop();
            }
            else
            {
                //栈顶元素的优先级大于等于当前的运算符,就将其输出
                while(priority_func(str[i]) <= priority_func(s.top()))
                {
                    str1 = str1+ " " + s.top();
                    s.pop();
                    //栈为空,停止
                    if(s.empty()) break;
                }
                s.push(str[i]);
            }
        }
    }
    //最后,如果不为空,就把所以的元素全部弹出
    while(!s.empty())
    {
        str1 = str1+ " " + s.top();
        s.pop();
    }
    string str2 = str1.substr(1,str1.size());
    str1 = str2;
    return str1;
}

#endif // NOAH_EXPRESSION_NORMALTORPN_H_INCLUDED

Main.cpp

#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "Noah_Cal_Expression_With_Stack.h"
void Menue_gui();
void func1();
void func2();
void func3();

int main()
{
    while(1){
        Menue_gui();
        int func;
        scanf("%d",&func);
        switch(func){
            case 0:
                exit(0);
            case 1:
                func1();break;
            case 2:
                func2();break;
            case 3:
                func3();break;
            default:
                printf("Input error! Please try again!");
        }
        printf("\n");
        system("pause");
    }
    return 0;
}

//菜单界面
void Menue_gui(){
    system("cls");//清屏
    printf("****************Polish, inverse Polish, and infix expression calculators*********************\n");
    printf("*********************************************************************************************\n");
    printf("Menue:\n");
    printf("\nExit this program------------------------------------------------------0.\n");
    printf("\nPolish expression calculator-------------------------------------------1.\n");
    printf("\nReverse Polish expression calculator-----------------------------------2.\n");
    printf("\nInfix expression calculator--------------------------------------------3.\n");
    printf("\n**********************************************************************************************\n");
    printf("Choose the function you want to use(input number):\n");
}

//功能1界面
void func1(){
    system("cls");//清屏
    printf("-----ENTER FUNCTION : Polish expression calculator--1.-----\n");
    printf("Input Polish expression(example:+ 2 * 3 - 5 1)\n");
    string polish_expression;
    polish_expression = input_expression();
    float reslut = float(Polish_type_calculate(polish_expression));
    printf("Result:%.2f",reslut);
}

//功能2界面
void func2(){
    system("cls");//清屏
    printf("-----ENTER FUNCTION : Inverse Polish expression calculator--2-----.\n");
    printf("Input Inverse Polish expression(example:2 3 5 1 - * +)\n");
    string Inverse_polish_expression;
    Inverse_polish_expression = input_expression();
    float reslut = float(Inverse_Polish_type_calculate(Inverse_polish_expression));
    printf("Result:%.2f",reslut);
}

//功能3界面
void func3(){
    system("cls");//清屏
    printf("-----ENTER FUNCTION : Infix expression calculator--3.-----\n");
    printf("Input Infix expression(example:4 + 2 * 3 – 10 / 5)\n");
    string Infix_expression;
    Infix_expression = input_expression();
    float reslut = float(Normal_type_calculate(Infix_expression));
    printf("Result:%.2f",reslut);
}

Je suppose que tu aimes

Origine blog.csdn.net/standingflower/article/details/127923498
conseillé
Classement