[Data Structure] Application of C++ Stack: Polish, Reverse Polish and Infix Expression Calculator

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

The author of this article is Noah Lazy Yangyang, a classmate of MF22, HKUST, to provide you with a homework idea, please do not copy directly! ! ! Let's learn together~

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

Table of contents

1. Description of the problem

1.1 Basic functions

1.2 Robustness

1.3 Normative

2. Description of the algorithm

2.1 Description of data structure

2.2 Description of program structure

3. Debugging analysis

4. Spatio-temporal analysis of the algorithm

5. Test results and analysis

code appendix

Noah_stack.h

Noah_Cal_Expression_With_Stack.h

Noah_expression_noemaltoRPN.h

Main.cpp


1. Description of the problem

1.1 Basic functions

1. Polish calculation

+ 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. Reverse Polish calculation

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. Infix calculation

(1) 4 + 2 * 3 – 10 / 5 calculation result, should output 8 (12 points);

(2)(4+2)*3 – 10 / 5 The calculation result should output 16 (12 points);

1.2 Robustness

  1. The program has certain handling for exceptions, such as illegal input, etc.

For example:

The input expression has illegal characters, (2 points)

For example: + 2 A, 2 3 A -, 4 + a

  1. The number of operands and operators in the input expression does not match (more operands or more operators) (4 points)

Such as: + 2 2 2 , 2 2 2 + , 2 + 2 2 , + + 2 2 , 2 2 + +, 2 + + 2

  1. Illegal input such as pairing cannot be completed by inputting expression brackets. (4 points)

Such as (4 + 2 * 3, 4 + 2) * 3.

1.3 Normative

  1. code comment
  2. program modularization
  3. Friendly human-computer interaction

2. Description of the algorithm

2.1 Description of data structure

The main data structure used in the program is the sequential stack.

 

Explanation of main variables:

variable

type

illustrate

sq_stack

structure

The structure of the stack

*base

The pointer to the bottom element of the stack

Used to access the bottom element of the stack, control the storage of the stack, calculate the number of elements in the station, etc.

*top

pointer to the top element of the stack

Used to access the top element of the stack, control the storage of the stack, calculate the number of elements in the station, etc.

stack_size

int

The memory space size of the sequential stack (the number of elements that can be stored)

expression

string

needs to evaluate the expression

STACK_INIT_SIZE

macro definition

Initialize storage space size

STACK_INCREMENT_SIZE

macro definition

Storage allocation increment size

STK_Item type

macro definition

The data type of the elements in the stack

2.2 Description of program structure

        The program mainly includes Noah_stack.h, Noah_expression_normaltoRPN.h, Noah_Cal_Expression_With_Stack.h header file and main.cpp main file, where Noah_stack.h is the implementation code header file of the stack data structure, and Noah_expression_normaltoRPN.h is to convert the infix expression to the suffix expression Formula (Reverse Polish) code collection header file, Noah_Cal_Expression_With_Stack.h is the code collection header file of the function of calculating different expressions realized by the call stack data structure and expression conversion code, main.cpp mainly realizes the menu and function interface Interaction and calls to functions in header files. Its specific structure is shown in the figure below.

 

3. Debugging analysis

Debugging function one: Polish expression calculator

Evaluate Polish expressions

 

Test data selection:

  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)

Problems and solutions:

  1. Since the io input obtains a string data type, it is necessary to recognize symbols and numbers, but when recognizing numbers with tens or higher digits, they are not recognized as a number at the beginning, but are recognized as multiple numbers. , the solution is to add the corresponding judgment control code to solve this problem.

Debugging function two: Inverse Polish expression calculator

Computes the reverse Polish expression

 

Test data selection:

  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)

Problems and solutions:

  1. The code at the beginning did not distinguish whether "10" is a number 1, a number 0, or a number 10. To solve this problem, a space needs to be added between each number and the operator when restricting input.

Debugging function three: Infix expression calculator

Evaluate infix expressions

 

Test data selection:

  1. 4 + 2 * 3 – 10 / 5 calculation result, should output 8 (12 points);
  2. (4+2)*3 – 10 / 5 calculation result, should output 16 (12 points);

Problems and solutions:

none

Debugging function four: Robustness test

 

Test data selection:

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

Problems and solutions:

none

4. Spatio-temporal analysis of the algorithm

(1)STK_Elemtype Polish_type_calculate(string expression)

Time complexity: O(n)

Space complexity: O(n)

(2)STK_Elemtype Inverse_Polish_type_calculate(string expression)

Time complexity: O(n)

Space complexity: O(n)

(3)STK_Elemtype Normal_type_calculate(string expression)

Time complexity: O(n)

Space complexity: O(n)

5. Test results and analysis

Test function one: Polish expression calculator

test case

result

analyze

+ 2 * 3 - 5 1

 

√, Polish calculation is correct

+ + 2 * 3 - 7 4 / 8 4

 

Debugging function two: Inverse Polish expression calculator

test case

result

analyze

2 3 5 1 - * +

 

√, the reverse Polish formula is calculated correctly

9 3 1 – 3 * + 10  2 / +

 

Test function three: Infix expression calculator

test case

result

analyze

4 + 2 * 3 – 10 / 5

 

√, the infix expression is calculated correctly

( 4 + 2) * 3 – 10 / 5

 

Debugging function four: robustness test

test case

result

analyze

1 + ( 5 * 6 – 10

 

a , a + 5

 

2 3 A –

 

4 + 2) * 3

 

+ + 2 2

 

code appendix

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

Guess you like

Origin blog.csdn.net/standingflower/article/details/127923498