nyoj-35

表达式求值的经典算法
编写代码对算术表达式求值的经典方法由 Donald Knuth 描述于 1962 年。
Knuth 将此概括为三个步骤:
1、对中缀表达式进行语法分析
2、中缀表达式到后缀表达式的转换
3、对后缀表达式求值 
注意到我们谈到的这个经典算法有些简化:算术表达式只包含操作数、二元操作符和一种括号。
此外,对于每个操作数和操作符,只用单个字符表示,使语法分析直观。
表达式表示法:
算术表达式中最常见的表示法形式有 中缀、前缀和 后缀表示法。
中缀表示法是书写表达式的常见方式,而前缀和后缀表示法主要用于计算机科学领域。
中缀表示法:
中缀表示法是算术表达式的常规表示法。称它为中缀表示法是因为每个操作符都位于
其操作数的中间,这种表示法只适用于操作符恰好对应两个操作数的时候
(在操作符是二元操作符如加、减、乘、除以及取模的情况下)。
对以中缀表示法书写的表达式进行语法分析时,需要用括号和优先规则排除多义性。
Syntax: operand1 operator operand2
Example: (A+B)*C-D/(E+F)
前缀表示法
前缀表示法中,操作符写在操作数的前面。这种表示法经常用于计算机科学,
特别是编译器设计方面。为纪念其发明家 ― Jan Lukasiewicz,
这种表示法也称 波兰表示法。
Syntax : operator operand1 operand2
Example : -*+ABC/D+EF
后缀表示法
在后缀表示法中,操作符位于操作数后面。后缀表示法也称 逆波兰表示法
(reverse Polish notation,RPN),因其使表达式求值变得轻松,所以被普遍使用。
Syntax : operand1 operand2 operator
Example : AB+C*DEF+/-
前缀和后缀表示法有三项公共特征:
操作数的顺序与等价的中缀表达式中操作数的顺序一致
不需要括号
操作符的优先级不相关
中缀转化为后缀算法:

a. 得到一操作符或操作数;
b. 若输入为操作数,则输出到数组,转a;
c. 若输入为‘(’,压栈,转a;
d. 若输入为‘)’,栈顶出栈,输出到数组,直至栈顶为‘(’,不输出到数组(抛弃),转a;
e. 若输入为操作符,
若栈空或栈顶为‘(’或操作符.忧先级大于栈顶操作符,压栈,转a
若操作符优先级小于栈顶操作符,则出栈,输出至数组,转e;
d. 若输入结束,出栈,输出到数组,直至栈空。
数组SNode中即为后缀表达式;

优先级可以根据需要分为 栈内优先级和栈外优先级
后缀表达式求值
对后缀表达式求值比直接对中缀表达式求值简单。在后缀表达式中,不需要括号,
而且操作符的优先级也不再起作用了。您可以用如下算法对后缀表达式求值:初始化一个空堆栈
从左到右读入后缀表达式,如果字符是一个操作数,把它压入堆栈。如果字符是个操作符,
弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,
后缀表达式的语法就不正确。到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,
那么堆栈应该为空。

#include<iostream>  
#include<string>  
#include<cstring>  
#include<stack>
#include<cstdio> 
#include<iomanip>  
using namespace std;  
struct oper  
{  
    double num;  
    char operate;  
};  
int judge(char ch)  
{  
    int ans=0;  
    switch(ch)  
    {  
	case '+': ans=1; break;  
    case '-': ans=2; break;  
    case '*': ans=3; break;  
    case '/': ans=4; break;  
    case '(': ans=5; break;  
	case ')': ans=6; break;  
    default : ans=7;  
    }  
    return ans;  
}  
int main()  
{  
   // freopen("d:\\test.txt","r",stdin);  
    int n;  
    oper op;  
    char str[1024];  
    oper suffix[1024];  
    int sufp;  
    stack<oper> Stack;  
    cin>>n;  
    while(n--)  
    {  
        memset(suffix,0,sizeof(suffix));  
        sufp=0;  
        cin>>str;  
        //中缀转化后缀  
        int current=0,len=strlen(str)-1;  
        while(current<len)  
        {  
            if(judge(str[current])==7)  
            {  
                sscanf(str+current,"%lf",&op.num);  
                op.operate='R';  
                while(1)  
					if(judge(str[++current])!=7)
						break;  
            }  
            else 
            {  
                sscanf(str+current,"%c",&op.operate);  
                op.num=0;  
                current++;  
            }   
            switch(judge(op.operate))  
            {  
                case 7: suffix[sufp++]=op; break;   //b. 若输入为操作数,则输出到数组,转a;
                case 5: Stack.push(op); break;		//c. 若输入为‘(’,压栈,转a;
                case 6:								//d. 若输入为‘)’,栈顶出栈,输出到数组,直至栈顶为‘(’,
													//不输出到数组(抛弃),转a;
                    while(Stack.top().operate!='(')  
                    {  
                        suffix[sufp++]=Stack.top();  
                        Stack.pop();  
                    }  
                    Stack.pop();  
                    break;  
                default:						
                    while(1)  
                    {  								//e. 若输入为操作符,若栈空或栈顶为‘(’或操作符.优先级大于栈顶操作符,压栈,转a
                        if(Stack.empty() || Stack.top().operate=='(' || judge(op.operate)-judge(Stack.top().operate)>=1)  
                        {  
                            Stack.push(op);  
                            break;  
                        }  
                        else						//若操作符优先级小于栈顶操作符,则出栈,输出至数组,转e;
                        {  
                            suffix[sufp++]=Stack.top();  
                            Stack.pop();  
                        }  
                    }  
            }  
        }  
        while(!Stack.empty())						//d. 若输入结束,出栈,输出到数组,直至栈空。
        {  
            suffix[sufp++]=Stack.top();  
            Stack.pop();  
        }  
        //后缀法计算    
        stack<double> ss;  
        for(current=0;current<sufp;current++)  
        {  
            if(suffix[current].operate=='R')  
                ss.push(suffix[current].num);  
            else 
            {  
                double t1=ss.top();  
                ss.pop();  
                double t2=ss.top();  
                ss.pop();  
                switch(judge(suffix[current].operate))  
                {  
                    case 1:ss.push(t2+t1); break;  
                    case 2:ss.push(t2-t1); break;  
                    case 3:ss.push(t2*t1); break;  
                    case 4:ss.push(t2/t1); break;  
                }  
            }            
        }  
        cout<<setiosflags(ios::fixed)<<setprecision(2)<<ss.top()<<endl;  
	}  
	return 0;
}  

  

你可能感兴趣的:(nyoj-35)