[Estrutura de dados] Aplicação da pilha C++: polonês, polonês reverso e calculadora de expressão infixa

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

O autor deste artigo é Noah Lazy Yangyang, um colega de classe do MF22, HKUST, para fornecer uma ideia de lição de casa, por favor, não copie diretamente! ! ! Vamos aprender juntos~

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

Índice

1. Descrição do problema

1.1 Funções básicas

1.2 Robustez

1.3 Normativa

2. Descrição do algoritmo

2.1 Descrição da estrutura de dados

2.2 Descrição da estrutura do programa

3. Análise de depuração

4. Análise espaço-temporal do algoritmo

5. Resultados e análises dos testes

apêndice de código

Noah_stack.h

Noah_Cal_Expression_With_Stack.h

Noah_expression_noemaltoRPN.h

Main.cpp


1. Descrição do problema

1.1 Funções básicas

1. Cálculo polonês

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

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

2. Cálculo polonês reverso

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

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

                        

3. Cálculo do infixo

(1) 4 + 2 * 3 – 10/5 resultado do cálculo, deve produzir 8 (12 pontos);

(2)(4+2)*3 – 10 / 5 O resultado do cálculo deve produzir 16 (12 pontos);

1.2 Robustez

  1. O programa tem certo tratamento para exceções, como entrada ilegal, etc.

Por exemplo:

A expressão de entrada contém caracteres inválidos, (2 pontos)

Por exemplo: + 2 A, 2 3 A -, 4 + a

  1. O número de operandos e operadores na expressão de entrada não corresponde (mais operandos ou mais operadores) (4 pontos)

Tais como: + 2 2 2 , 2 2 2 + , 2 + 2 2 , + + 2 2 , 2 2 + +, 2 + + 2

  1. A entrada ilegal, como o emparelhamento, não pode ser concluída inserindo colchetes de expressão. (4 pontos)

Tal como (4 + 2 * 3, 4 + 2) * 3.

1.3 Normativa

  1. comentário de código
  2. modularização do programa
  3. Interação amigável humano-computador

2. Descrição do algoritmo

2.1 Descrição da estrutura de dados

A principal estrutura de dados utilizada no programa é a pilha sequencial.

 

Explicação das principais variáveis:

variável

tipo

ilustrar

sq_stack

estrutura

A estrutura da pilha

*base

O ponteiro para o elemento inferior da pilha

Usado para acessar o elemento inferior da pilha, controlar o armazenamento da pilha, calcular o número de elementos na estação, etc.

*principal

ponteiro para o elemento superior da pilha

Usado para acessar o elemento superior da pilha, controlar o armazenamento da pilha, calcular o número de elementos na estação, etc.

Tamanho da pilha

int

O tamanho do espaço de memória da pilha sequencial (o número de elementos que podem ser armazenados)

expressão

corda

precisa avaliar a expressão

STACK_INIT_SIZE

definição de macro

Inicializar o tamanho do espaço de armazenamento

STACK_INCREMENT_SIZE

definição de macro

Tamanho do incremento de alocação de armazenamento

STK_Tipo de item

definição de macro

O tipo de dados dos elementos na pilha

2.2 Descrição da estrutura do programa

        O programa inclui principalmente Noah_stack.h, Noah_expression_normaltoRPN.h, arquivo de cabeçalho Noah_Cal_Expression_With_Stack.h e arquivo principal main.cpp, onde Noah_stack.h é o arquivo de cabeçalho do código de implementação da estrutura de dados da pilha e Noah_expression_normaltoRPN.h é para converter a expressão infixa para o arquivo de cabeçalho de coleta de código de fórmula de expressão de sufixo (polonês reverso), Noah_Cal_Expression_With_Stack.h é o arquivo de cabeçalho de coleta de código da função de cálculo de diferentes expressões realizadas pela estrutura de dados da pilha de chamadas e código de conversão de expressão, main.cpp implementa principalmente o menu e interface de função Interação e chamadas para funções em arquivos de cabeçalho. Sua estrutura específica é mostrada na figura abaixo.

 

3. Análise de depuração

Função de depuração um: calculadora de expressão polonesa

Avalie as expressões polonesas

 

Seleção de dados de teste:

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

Problemas e soluções:

  1. Como a entrada io obtém um tipo de dados string, é necessário reconhecer símbolos e números, mas ao reconhecer números com dezenas ou dígitos maiores, eles não são reconhecidos como um número no início, mas são reconhecidos como números múltiplos. , a solução é adicionar o código de controle de julgamento correspondente para resolver este problema.

Função de depuração dois: calculadora de expressão polonesa inversa

Calcula a expressão polonesa reversa

 

Seleção de dados de teste:

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

Problemas e soluções:

  1. O código no início não distinguia se "10" é um número 1, um número 0 ou um número 10. Para resolver esse problema, é necessário adicionar um espaço entre cada número e o operador ao restringir a entrada.

Função de depuração três: calculadora de expressão infixa

Avaliar expressões infixas

 

Seleção de dados de teste:

  1. 4 + 2 * 3 – 10/5 resultado do cálculo, deve produzir 8 (12 pontos);
  2. (4+2)*3 – 10/5 resultado do cálculo, deve produzir 16 (12 pontos);

Problemas e soluções:

nenhum

Função de depuração quatro: teste de robustez

 

Seleção de dados de teste:

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

Problemas e soluções:

nenhum

4. Análise espaço-temporal do algoritmo

(1)STK_Elemtype Polish_type_calculate(expressão de string)

Complexidade de tempo: O(n)

Complexidade do espaço: O(n)

(2)STK_Elemtype Inverse_Polish_type_calculate(expressão de string)

Complexidade de tempo: O(n)

Complexidade do espaço: O(n)

(3)STK_Elemtype Normal_type_calculate(expressão de string)

Complexidade de tempo: O(n)

Complexidade do espaço: O(n)

5. Resultados e análises dos testes

Função de teste um: calculadora de expressão polonesa

caso de teste

resultado

analisar

+ 2 * 3 - 5 1

 

√, o cálculo polonês está correto

+ + 2 * 3 - 7 4/8 4

 

Função de depuração dois: calculadora de expressão polonesa inversa

caso de teste

resultado

analisar

2 3 5 1 - * +

 

√, a fórmula polonesa reversa é calculada corretamente

9 3 1 – 3 * + 10 2 / +

 

Função de teste três: calculadora de expressão infixa

caso de teste

resultado

analisar

4 + 2 * 3 – 10/5

 

√, a expressão infixa é calculada corretamente

(4 + 2) * 3 – 10/5

 

Função de depuração quatro: teste de robustez

caso de teste

resultado

analisar

1 + ( 5 * 6 – 10

 

um, um + 5

 

2 3 A –

 

4 + 2) * 3

 

+ + 2 2

 

apêndice de código

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);
}

Acho que você gosta

Origin blog.csdn.net/standingflower/article/details/127923498
Recomendado
Clasificación