表达式求值(中缀表达式——后缀表达式——求值)

来源:互联网 发布:linux 扫描磁盘的命令 编辑:程序博客网 时间:2024/06/16 00:16

        表达式求值,属于数据结构——的典型应用。使用后缀表达式的与原因,是因为在求值的过程中,不需要考虑操作符的优先级。(结合性仍需要考虑)

        但是一般的书上只讲到如何处理二元操作符,并且结合性都是从左到右结合的。这里的实现能够处理一元操作符,并且能够处理从右向左结合的幂乘'^'操作符。

功能需求

        给定一个中缀表达式,求出该表达式的值。
        要求支持“加减乘除 + - * /、取余 %、幂运算 ^、一元正负号 + -、括号 ()、数的科学表示法符号 E e”,其中含有一元操作符'+ -',也含有从右向左结合性的操作符'^',注意操作数的位数可以为多位。

分析

        需要考虑三个方面:① 优先级; ② 结合性; ③ 几元操作符;

        优先级:若操作符的优先级不同,那么先计算优先级高的。

        结合性:若操作符的优先级相同,那么先计算优先级的结合性决定求值顺序。

        几元操作符:一元和二元操作符,决定了参与求值的操作数的个数。

处理方法

        1. 利用数字0,将一元操作转化为二元操作,例如将"-3"转化为"0-3";

        2. 将操作符按照优先级分类,确定各个操作符的优先级;

        3. 结合性不同的操作符,由于数量较少(这里只有'^'),处理时单独判断;

具体步骤

        1. 判断是否有不匹配的括号

        2. 预处理中缀表达式
                2.1 判断是否有不能处理的字符;
                2.2 去除所有的空格;
                2.3 处理一元操作符'+'和'-':
                        2.3.1 如果是在开始位置,在开始处添加"0";
                        2.3.2 如果是在“非数字字符”(右括号‘)’除外)之后,那么先在一元操作符前插入"(0",然后在一个“完整的数字”或者“括号后面”添加右括号")";

        3. 中缀转化为后缀表达式 (利用“操作符栈”)
            遍历中缀表达式:
                3.1 如果是操作数,读取其所有的位,然后进入后缀表达式队列;
                3.2 如果是操作符( + – * / ^ % )
                        3.2.1 如果“操作符栈”为空,直接入栈;
                        3.2.2 如果当前操作符优先级>栈顶元素优先级,那么入栈;
                        3.2.3 如果当前操作符优先级<栈顶元素优先级,那么栈顶操作符出栈,循环执行;
                        3.2.4 如果当前操作符优先级=栈顶元素优先级,如果当前元素是右结合性,那么入栈;否则,栈顶元素出栈;循环执行。
                3.3 如果是左括号'(',直接入栈
                3.4 如果是右括号')',如果栈非空,那么栈顶元素出栈,直到遇到左括号'(';
                3.5 遍历结束中,将操作符栈中的元素依次出栈,添加到后缀表达式队列中。
        4. 计算后缀表达式
            从后缀表达式队列中依次取出元素
                4.1 如果是操作数,那么将其压入“结果栈”中;
                4.2 如果是操作符,从“结果栈”中取出两个元素,进行计算。(注意从栈中取元素的顺序和操作数的顺序是相反的)
                遍历后缀表达式结束后,“结果栈”中的元素就是最终的结果。

具体代码

/** * 中缀表达式-->后缀表达式-->表达式求值 * */#include <cstdlib>#include <iostream>#include <string>#include <cctype>#include <set>#include <queue>#include <stack>#include <map>#include <cmath>using namespace std;/** * 判断是否为操作符 * 参数: *      ch : 待判断的字符 * 返回值: *      是操作符,返回true;否则返回false; */bool is_operator(char ch) {    set<char> operator_set;    operator_set.insert('+');    operator_set.insert('-');    operator_set.insert('*');    operator_set.insert('/');    operator_set.insert('%');    operator_set.insert('^');    return operator_set.find(ch) != operator_set.end();}/** * 比较两个操作符的优先级 */int compare_priority(char a, char b) {    map<char, int> operator_priority;    operator_priority.insert(make_pair('+', 1));    operator_priority.insert(make_pair('-', 1));    operator_priority.insert(make_pair('*', 2));    operator_priority.insert(make_pair('/', 2));    operator_priority.insert(make_pair('%', 2));    operator_priority.insert(make_pair('^', 3));    return operator_priority[a]-operator_priority[b];}/** * 判断是否有不匹配的括号 */bool is_bracket_valid(string infix) {    stack<char> bracket;    for(int i=0; i<infix.size(); i++) {        if(infix[i]=='(') {            bracket.push(infix[i]);        } else if(infix[i]==')') {            if(bracket.empty()) {                cout<<"有右括号没有匹配"<<endl;                return false;            }            bracket.pop();        }    }    if(!bracket.empty()) {        cout<<"有左括号没有匹配"<<endl;        return false;    }    return true;}/** * 预处理 * 参数: *      infix:预处理前的中序表达式 * 返回值: *      处理后的中序表达式 * 步骤: *      1. 去除空格 *      2. 判断是否含有不能处理的字符 *      3. 处理一元操作符 '+'和'-' */string preprocess(const string infix) {    string result = infix;    //去除空格    size_t index;    while((index = result.find(string(" "))) != string::npos) {        result.erase(index, 1);    }    cout<<"去除空格后  "<<result<<""<<endl;    //初始化能够处理的字符集合    set<char> valid_char_set;//能够处理的字符    for(int i=0; i<=9; i++) {        valid_char_set.insert(i+'0');    }    valid_char_set.insert('+');    valid_char_set.insert('-');    valid_char_set.insert('*');    valid_char_set.insert('/');    valid_char_set.insert('%');    valid_char_set.insert('^');    valid_char_set.insert('(');    valid_char_set.insert(')');    valid_char_set.insert('e');//'e'和'E'为科学计数法    valid_char_set.insert('E');    valid_char_set.insert('.');//小数点    for(int i=0; i<result.size(); i++) {        //如果字符不在valid_char_set,说明有不能处理的字符,结束程序        if(valid_char_set.find(result[i]) == valid_char_set.end()) {            cout<<"中缀表达式中有非法字符: "<<result[i]<<"  "<<i<<endl;            exit(-1);        }    }    //处理一元操作符    for(int i=0; i<result.size(); i++) {        char temp = result[i];        if(temp != '+' && temp != '-') {            continue;        }//        cout<<i<<"   "<<result<<"   "<<result[i]<<endl;        if(i==0) { //表达式开始位置的 '-'            result.insert(i, 1, 0+'0');        } else if(i-1>=0 && !isdigit(result[i-1]) && result[i-1]!=')') { //一元+-,紧跟着其他符号后面            result.insert(i, "(0");            int j = i+3;            int bracket_count=0;//如果有括号,应包含括号            for(; j<result.size(); j++) {                if(isdigit(result[j]) || result[j]=='.') {                    continue;                } else if(result[j]=='(') {                    ++bracket_count;                } else if(result[j]==')') {//                    --left_bracket_count;                    if((--bracket_count) == 0) {                        break;                    }                } else if(bracket_count==0) {                    break;                }            }            i = j;            result.insert(j, ")");        }    }    return result;}/** * 中缀表达式-->后缀表达式 */queue<string> infix_to_post(string infix) {    queue<string> postfix;//后缀表达式队列    stack<char> operator_stack;//转换过程中,用来存储操作符的栈    set<char> valid_operand_set;//操作数 中的字符    for(int i=0; i<=9; i++) {        valid_operand_set.insert(i+'0');    }    valid_operand_set.insert('.');    valid_operand_set.insert('e');    valid_operand_set.insert('E');    for(int i=0; i<infix.size(); i++) {        cout<<endl;        char ch = infix[i];        cout<<"序号:"<<"  "<<i<<"  字符:  "<<ch<<endl;        if(infix[i]=='(') {//左括号            operator_stack.push(infix[i]);        } else if(infix[i]==')') {//右括号            while(!operator_stack.empty() && operator_stack.top()!='(') {                postfix.push(string(1, operator_stack.top()));                operator_stack.pop();            }            operator_stack.pop();//将"("出栈        } else if(is_operator(infix[i]) == true) { //是操作符(不包含 左、右括号)            if(operator_stack.empty()) { //操作符栈为空                operator_stack.push(infix[i]);                continue;            }            //操作符栈非空            char top_stack = operator_stack.top();            //将栈中“较高和相等”优先级的操作符放到 后缀表达式中。            //终止条件为:当前操作符>栈顶操作符优先级,或优先级相等、但栈顶操作符的结合性是“从右向左”。            while(compare_priority(infix[i], top_stack)<=0) {                //优先级相等,但栈顶操作符结合性为从右向左,这里特指'^'                if(compare_priority(infix[i], top_stack)==0 && infix[i]=='^') {   //因为'^'的结合性从右向左,所以单独处理                    break;                }                //当前操作符<=栈顶操作符优先级,当前操作符结合性为从左到右                postfix.push(string(1, top_stack));                operator_stack.pop();                if(!operator_stack.empty()) {                    top_stack = operator_stack.top();                } else {                    break;                }            }            //将当前操作符入栈            operator_stack.push(infix[i]);        } else {//操作数            string current_operator;            int j=i;            while(valid_operand_set.find(infix[j]) != valid_operand_set.end()) {                current_operator += infix[j];                ++j;            }            postfix.push(current_operator);            i=j-1;//因为for循环,每次都会执行i++        }                //打印处理过程        cout<<"当前栈顶: "<<(operator_stack.empty() ?' ': operator_stack.top())<<endl;        queue<string> temp_queue = postfix;        cout<<"当前后缀表达式: ";        while(temp_queue.size()>0) {            cout<<temp_queue.front()<<"  ";            temp_queue.front();            temp_queue.pop();        }        cout<<endl;    }    //最后将栈中内容全部取出来    while(!operator_stack.empty()) {        postfix.push(string(1, operator_stack.top()));        operator_stack.pop();    }    return postfix;}/** * 计算两个操作数 */double calculate_two(double a, double b, string operand) {    double result;    if(operand == "+") {        result = a+b;    } else if(operand == "-") {        result = a-b;    } else if(operand == "*") {        result = a*b;    } else if(operand == "/") {        if(b==0) {            cout<<"除数不能为0"<<endl;            exit(-1);        }        result = a/b;    } else if(operand == "%") {        result = (static_cast<int>(a)) % (static_cast<int>(b));    } else if(operand == "^") {        result = pow(a, b);    }    return result;}//对后缀表达式,进行计算double calculate_post(queue<string>& post) {    stack<double> result_stack;    while(!post.empty()) {        string temp = post.front();        post.pop();        if(is_operator(temp[0])) { //是操作符            if(result_stack.size()<2) {                cout<<"表达式错误"<<endl;                exit(-1);            }            //从栈中取出两个元素,计算并将结果压入栈中            double operand2 = result_stack.top();            result_stack.pop();            double operand1 = result_stack.top();            result_stack.pop();            double m = calculate_two(operand1, operand2, temp);            result_stack.push(m);        } else { //操作数            double temp_operand = atof(temp.c_str());            result_stack.push(temp_operand);        }    }    return result_stack.top();}int main(int argc, char **argv) {    string infix;//    infix = "10e2+3*4-5%2-2^-(4/2)+.2 + 2^1^3";//结果为:1012.95    cout<<"请输入中缀表达式: "<<endl;    getline(cin, infix);    cout<<endl<<"原始前缀表达式: "<<infix<<endl;    //1. 检测括号是否匹配    bool valid = is_bracket_valid(infix);    if(valid){        cout<<endl<<"括号匹配"<<endl<<endl;    }else{        return 0;    }        //2.预处理中缀表达式    string result_infix = preprocess(infix);    cout<<"预处理以后:"<<result_infix<<endl;    //3. 中缀 转 后缀    queue<string> result_post = infix_to_post(result_infix);    //打印后缀表达式    queue<string> temp = result_post;    cout<<"后缀表达式: ";    while(!temp.empty()) {        cout<<temp.front()<<"  ";        temp.pop();    }    cout<<endl;        //4. 计算结果    double result = calculate_post(result_post);    cout<<endl<<"计算结果: "<<result<<endl;        return 0;}

运行结果:

请输入中缀表达式:10e2+3*4-5%2-2^-(4/2)+.2 + 2^1^3原始前缀表达式: 10e2+3*4-5%2-2^-(4/2)+.2 + 2^1^3括号匹配去除空格后  10e2+3*4-5%2-2^-(4/2)+.2+2^1^3预处理以后:10e2+3*4-5%2-2^(0-(4/2))+.2+2^1^3序号:  0  字符:  1当前栈顶:当前后缀表达式: 10e2序号:  4  字符:  +序号:  5  字符:  3当前栈顶: +当前后缀表达式: 10e2  3序号:  6  字符:  *当前栈顶: *当前后缀表达式: 10e2  3序号:  7  字符:  4当前栈顶: *当前后缀表达式: 10e2  3  4序号:  8  字符:  -当前栈顶: -当前后缀表达式: 10e2  3  4  *  +序号:  9  字符:  5当前栈顶: -当前后缀表达式: 10e2  3  4  *  +  5序号:  10  字符:  %当前栈顶: %当前后缀表达式: 10e2  3  4  *  +  5序号:  11  字符:  2当前栈顶: %当前后缀表达式: 10e2  3  4  *  +  5  2序号:  12  字符:  -当前栈顶: -当前后缀表达式: 10e2  3  4  *  +  5  2  %  -序号:  13  字符:  2当前栈顶: -当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2序号:  14  字符:  ^当前栈顶: ^当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2序号:  15  字符:  (当前栈顶: (当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2序号:  16  字符:  0当前栈顶: (当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0序号:  17  字符:  -当前栈顶: -当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0序号:  18  字符:  (当前栈顶: (当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0序号:  19  字符:  4当前栈顶: (当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4序号:  20  字符:  /当前栈顶: /当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4序号:  21  字符:  2当前栈顶: /当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2序号:  22  字符:  )当前栈顶: -当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /序号:  23  字符:  )当前栈顶: ^当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -序号:  24  字符:  +当前栈顶: +当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -  ^  -序号:  25  字符:  .当前栈顶: +当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -  ^  -  .2序号:  27  字符:  +当前栈顶: +当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -  ^  -  .2  +序号:  28  字符:  2当前栈顶: +当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -  ^  -  .2  +  2序号:  29  字符:  ^当前栈顶: ^当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -  ^  -  .2  +  2序号:  30  字符:  1当前栈顶: ^当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -  ^  -  .2  +  2  1序号:  31  字符:  ^当前栈顶: ^当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -  ^  -  .2  +  2  1序号:  32  字符:  3当前栈顶: ^当前后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -  ^  -  .2  +  2  1  3后缀表达式: 10e2  3  4  *  +  5  2  %  -  2  0  4  2  /  -  ^  -  .2  +  2  1  3  ^  ^  +计算结果: 1012.95Press any key to continue.

本文链接:http://blog.csdn.net/daheiantian/archive/2011/03/19/6553713.aspx

原创粉丝点击