expression evaluation


The general idea of ​​expression evaluation is to convert an arithmetic expression with operator precedence order into a postfix expression without operator precedence, thereby evaluating the value.



three expressions


1. Prefix expression (Polish):

A prefix expression is an arithmetic expression without parentheses, which writes the operator before and the operand after (for example, the prefix expression of "3+4" is "+34").

2. Infix expression:
an arithmetic expression that can contain parentheses and the operator is in the middle of the operand (the infix expression of "3+4" is still "3+4"), the infix expression is what people usually use Arithmetic representation of .

3. Postfix expression (reverse Polish):
an arithmetic expression that does not contain parentheses, and the operator is placed after the two operands (for example, the postfix expression of "3+4" is "34+").

The above three expressions can be converted to each other, and there are many conversion methods. Common ones can be through queues and stacks, binary tree traversal, etc. We will introduce the former method below.



Infix expression —> Postfix expression


Steps:

1. Build a queue and a stack; read arithmetic expressions from left to right, push operands onto the queue, and push operators onto the stack.


2. When read as an operator, there are the following four cases:

1) + or - sign, pop the operator on the stack and push it into the queue until the stack is empty or encounters a left parenthesis; then push itself onto the stack.

2) * or / sign, pop the operator on the stack and push it into the queue until the stack is empty or encounters a left parenthesis/plus/minus sign; then push itself onto the stack.

3) ")", pop the operator on the stack and push it into the queue until the left parenthesis is encountered (the left parentheses are popped from the stack, but not pushed into the queue).

4) The "(" sign pushes itself into the stack.


3. When the arithmetic expression is read from left to right, pay attention to read out all the operators in the stack and push them into the queue in sequence (in order to enable the operators to be pushed into the double type queue, the operator can be set as special numbers).


Through the above three steps, infix expressions can be converted into postfix expressions. As long as the values ​​in the queue are output in order, the result is a postfix expression.



Let's take an example to convert " 3*(10+9/2)-7*2 " into a suffix expression. The process is shown in the following figure:



After getting the transformed postfix expression, how should the result be calculated?



Postfix expression evaluation


Infix evaluation requires consideration of operator precedence order, while postfix does not. Calculations in postfix expressions are performed in the order in which the operators appear, strictly from left to right, and the precedence rules of operators are no longer considered.

Steps:

1. Build a queue and a stack. The queue initially stores the suffix expression, and the stack is initially empty.

2. Read the element from the queue. If the element is an operand, pop the queue and push it into the stack; if the element is an operator, pop two operands from the stack. After the three obtain the result, push the result. into the stack.

3. Repeat step 2, and finally the operand in the stack is the value of the entire arithmetic expression.


Let's take a look at the process of finding the value of the suffix " 3 10 9 2 / + * 7 2 * - " from the perspective of the stack:

Postfix evaluation is performed from left to right, first calculate " 9 2 / ", and replace the original position after obtaining the result, that is, " 3 10 [ 9 2 / ] " to obtain " 3 10 [ 4.5 ] " ([] is the replacement part); the operation continues, "3 [ 14.5 ] " is obtained from " 3 [ 10 4.5 + ] "; " [ 43.5 ] " is obtained from " [ 3 14.5 * ] "; then " 43.5 [ 7 2 * ] " Get " 43.5 [ 14 ] "; the last step is " [ 29.5 ] " from " [ 43.5 14 - ] ", 29.5 is the final answer.



accomplish


Take an ACM question as an example, expression evaluation

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>

using namespace std;

intmain()
{
    //Evaluation can complete the calculation of decimal, multi-digit, signed and parenthesized expressions

    vector<double> pp,qq,zz;
    //pp as a queue for infix to suffix and postfix evaluation
    //qq is used as a stack to store operators when infix to suffix
    //zz is used as a stack to store operands during postfix evaluation
    char p[1005]; //Store operation expression
    int i,n;
    scanf("%d",&n); //Number of input groups
    while(n--)
    {
        // Convert infix expressions to postfix expressions
        scanf("%s",p); //Enter the operation expression
        if(strcmp(p,"0")==0)
        {
            break;
        }
        for(i=0;p[i]!='\0';i++)//Read the operation expression from left to right
        {
            double s=0; //s represents the operand waiting to be pushed into the queue
            int t=-1,flag=0; //t is used to record the number of consecutive 0s following the decimal point
            loop:
            while((p[i]>='0'&&p[i]<='9')||p[i]=='.')//Read consecutive numbers or decimal points and use it as an operand
            {
                if(!flag)
                {
                    flag=1; //Indicates that post-processing is required
                }
                if(p[i]=='.') //find decimal point
                {
                    t=0; //Prepare to record the number of 0s after the decimal point, initialized here
                }
                else
                {
                    if(t!=-1)
                    {
                        t++; //Add 1 to the number of 0s immediately after the decimal point
                    }
                    s=s*10+p[i]-'0'; //Convert character operand to numeric operand
                }
                i++;
            }
            if(flag) //post processing and push the operand into the queue
            {
                if(t!=-1) //There is a decimal point
                {
                    s=s*1.0/pow(10,t);//Add decimal point
                }
                if(flag==2)
                {
                    s=-s;// becomes negative
                }
                pp.push_back(s); //Push the operand into the queue
                i--; //This bit is a symbol and cannot be recorded, so this bit needs to be recorded in the next loop
            }
            else if(p[i]==')') //read closing parenthesis
            {
                //The operator on the stack is pushed into the queue until the stack is empty, or the left parenthesis is encountered
                while(!qq.empty()&&qq.back()!=-0.1050110)
                {
                    pp.push_back(qq.back()); //Push the operator on the stack into the queue
                    qq.pop_back(); //Pop the operator off the stack
                }
                if(!qq.empty())
                {
                    qq.pop_back(); // Pop the left parenthesis off the stack
                }
            }
            else if(p[i]=='(') //read left parenthesis
            {
                qq.push_back(-0.1050110); //Push the left parenthesis into a digital mark and push it onto the stack
            }
            else if(p[i]=='*'||p[i]=='/') //read multiplication or division
            {
                //The operator on the stack is pushed into the queue until the stack is empty, or the left parenthesis, plus sign, minus sign is encountered
                while(!qq.empty()&&(qq.back()==-0.1040110||qq.back()==-0.1030110)&&qq.back()!=-0.1050110)
                {
                    pp.push_back(qq.back()); //Push the operator on the stack into the queue
                    qq.pop_back(); //Pop the operator off the stack
                }
                if(p[i]=='*')
                {
                    qq.push_back(-0.1040110);//Push the multiplication sign into a digital mark and push it into the stack
                }
                else if(p[i]=='/')
                {
                    qq.push_back(-0.1030110);//Change the division sign into a digital mark and push it onto the stack
                }
            }
            else if(p[i]=='+'||p[i]=='-') //read plus or minus sign
            {
                //When the bit is in the first position of the operation expression or there is an operator in front of the bit (that is, the bit indicates positive or negative)
                if(i==0||p[i-1]=='+'||p[i-1]=='-'||p[i-1]=='*'||p[i-1]=='/'||p[i-1]=='(')
                {
                    if(p[i]=='-')
                    {
                        flag=2;//Negative flag
                    }
                    i++; //move to the next bit of the expression
                    goto loop; //Jump to continuous reading number
                }
                //The operator on the stack is pushed into the queue until the stack is empty, or the left parenthesis is encountered
                while(!qq.empty()&&qq.back()!=-0.1050110)
                {
                    pp.push_back(qq.back()); //Push the operator on the stack into the queue
                    qq.pop_back(); //Pop the operator off the stack
                }
                if(p[i]=='+')
                {
                    qq.push_back(-0.1020110);//Turn the plus sign into a digital mark and push it onto the stack
                }
                else if(p[i]=='-')
                {
                    qq.push_back(-0.1010110);//Turn the minus sign into a digital mark and push it into the stack
                }
            }
        }
        while(!qq.empty())//Pop all operators on the stack and push them into the queue in order
        {
            pp.push_back(qq.back());
            qq.pop_back();
        }

        //Print the postfix expression of the operation expression
        /*cout<<"Infix expression is converted to postfix expression: ";
        for(i=0;i<pp.size();i++)
        {
            if(pp[i]==-0.1040110)
            {
                cout<<"*"<<" ";
            }
            else if(pp[i]==-0.1030110)
            {
                cout<<"/"<<" ";
            }
            else if(pp[i]==-0.1020110)
            {
                cout<<"+"<<" ";
            }
            else if(pp[i]==-0.1010110)
            {
                cout<<"-"<<" ";
            }
            else
            {
                cout<<pp[i]<<" ";
            }
        }
        cout<<endl;*/

        // Calculate the result of the postfix expression
        for(i=0;i<pp.size();i++) //traverse the queue of suffix expressions
        {
            double a,b;
            if(pp[i]==-0.1010110) //The operator is a minus sign
            {
                a=zz.back(); //Remove the first operand from the stack
                zz.pop_back(); //Pop stack
                b=zz.back(); // remove the second operand from the stack
                zz.pop_back(); //Pop stack
                zz.push_back(ba);//Push the result of the operand operation onto the stack
            }
            else if(pp[i]==-0.1020110)//The operator is a plus sign
            {
                a=zz.back();
                zz.pop_back();
                b=zz.back();
                zz.pop_back();
                zz.push_back(b+a);
            }
            else if(pp[i]==-0.1030110)//The operator is the division sign
            {
                a=zz.back();
                zz.pop_back();
                b=zz.back();
                zz.pop_back();
                zz.push_back(b*1.0/a);
            }
            else if(pp[i]==-0.1040110)//The operator is a multiplication sign
            {
                a=zz.back();
                zz.pop_back();
                b=zz.back();
                zz.pop_back();
                zz.push_back(b*a);
            }
            else//Not operator
            {
                zz.push_back(pp[i]);//Push the operand onto the stack
            }
        }
        //cout<<"Calculation result: ";
        printf("%.2lf\n",zz.back());//The value in the stack is the value of the expression
        pp.clear();qq.clear();zz.clear();//清理
    }
    return 0;
}

Using the above ideas can solve many similar problems:

Simple calculator , big brother Qiushi does arithmetic , prefix calculation



expand


Based on the above algorithm ideas, combined with Java's Swing package, I wrote a calculator tool (the comments are not complete, sorry).




If there is any inappropriateness in the text, I hope to accommodate and point out, thank you


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325441654&siteId=291194637