解析表达式—C++实现

  1. 中缀、前缀、后缀表达式

对于一个人可识别的表达式:1+(2+3)*4-5

根据操作符的位置不同分为:

①中缀表达式:1+(2+3)*4-5

②前缀表达式:- + 1 * + 2 3 4 5

③后缀表达式:1 2 3 + 4 * + 5 -

前缀表达式和后缀表达式里面已经包含了计算顺序,因此不需要括号来确定优先级

  1. 中缀转前缀

2.1 中缀转前缀

①按运算符优先级对所有的运算单位加括号

((1+((2+3)*4))-5)

②将运算符移动到对应括号的前面

(- ( + 1( * ( + 2 3 ) 4 )) 5 )

③去掉括号,得到前缀表达式

    • 1 * + 2 3 4 5

转换的计算机实现:

(1)表达式树

(2)栈

①两个栈,运算符栈S1、存储中间结果栈S2

②从右到左扫描表达式

③遇到操作数,压栈S2

④遇到运算符,比较其与S1栈顶运算符优先级

若S1为空,或栈顶为右括号 ')' ,则此运算符入栈S1

若优先级比栈顶运算符高或相等,则此运算符入栈S1

若比栈顶优先级低,将S1栈顶运算符出栈压到S2里面,然后继续与S1栈顶运算符比较。重复④

⑤遇到括号

右括号直接压入S1

左括号,则依次弹出S1栈顶运算符到S2,直到遇到右括号,此时将这一对括号丢弃

⑥重复直到表达式最左边

⑦将S1剩余运算符依次弹出压到S2

⑧依次弹出S2中元素,得到前缀表达式

1 string midexToPreex(string &preex)
 2 {
 3     set<char> ops = {'+','-','*','/'};
 4     map<char,int> priority = {{'+',1},{'-',1},{'*',2},{'/',2}};
 5     ostringstream strstream;
 6 //    string *res = new string();
 7     stack<node> s1,s2;
 8     int preex_len = preex.size();
 9     struct node temp;
10     for(int i=preex_len-1;i>=0;--i) {
11         if(preex[i] == ' ' || preex[i] == '\t') {
12             continue;
13         }
14         else if((preex[i]>='0' && preex[i]<='9') || preex[i] =='.') { //遇到操作数
15             ostringstream strtmp;
16             stack<char> num_tmp;
17             if(preex[i] != '.') {  //对于15. 这种数,去掉后面的点,看作int类型
18                 num_tmp.push(preex[i]);
19             }
20 
21 //            strtmp<<preex[i];
22             for(int j=i-1;j>=0;j--) { //这里还需要修改
23                 if(preex[j]>='0'&& preex[j]<='9' || preex[j] =='.') {
24                     num_tmp.push(preex[j]);
25 //                    strtmp<<preex[j];
26                     i--;
27                 }
28                 else if(preex[j] == ' ' || preex[j] == '\t') {
29                     i--;
30                 }
31                 else {
32                     break;
33                 }
34             }
35             while(!num_tmp.empty()) {
36                 strtmp<<num_tmp.top();
37                 num_tmp.pop();
38             }
39             temp.num = strtmp.str();
40             temp.flag = true;
41             s2.push(temp);
42         }
43         else if(ops.find(preex[i]) != ops.end()) { //如果是运算符
44             if(s1.empty() || (!s1.top().flag && s1.top().op==')')) {
45                 temp.flag = false;
46                 temp.op = preex[i];
47                 s1.push(temp);
48             }
49             else if(priority[preex[i]] >= priority[s1.top().op]) {
50                 temp.flag = false;
51                 temp.op = preex[i];
52                 s1.push(temp);
53             }
54             else if(priority[preex[i]] < priority[s1.top().op]) {
55                 while(!(s1.empty() || s1.top().op==')' || priority[preex[i]] >= priority[s1.top().op])) {
56                     s2.push(s1.top());
57                     s1.pop();
58                 }
59                 temp.flag = false;
60                 temp.op = preex[i];
61                 s1.push(temp);
62             }
63         }
64         else if(preex[i] == ')') {
65             temp.flag = false;
66             temp.op = preex[i];
67             s1.push(temp);
68         }
69         else if(preex[i] == '(') {
70             while(s1.top().op != ')') {
71                 s2.push(s1.top());
72                 s1.pop();
73             }
74             s1.pop();//丢弃右括号
75             //此左括号不作处理,相当于丢弃了
76         }
77         else {
78             break;
79         }
80     }
81     while(!s1.empty()) {
82         s2.push(s1.top());
83         s1.pop();
84     }
85     while(!s2.empty()) {
86         if(s2.top().flag) {
87             strstream<<s2.top().num<<" ";
88         }
89         else {
90             strstream<<s2.top().op<<" ";
91         }
92         s2.pop();
93     }
94     return strstream.str();
95 }

2.2 前缀表达式解析计算

①从右到左扫描表达式

②遇到数字,则数字压栈,遇到运算符,取出栈顶的两个数做运算:栈顶 op 次顶,结果入栈

③重复直到表达式最左侧

1 template<typename T>
 2 T cal(T n1,T n2,char op)
 3 {
 4     T res;
 5     switch(op) {
 6         case '+':res=n1+n2;break;
 7         case '-':res=n1-n2;break;
 8         case '*':res=n1*n2;break;
 9         case '/':res=n1/n2;break;
10         default:break;
11     }
12     return res;
13 }
14 
15 int cal_prerc(string &preex)
16 {
17     int ex_size = preex.size();
18     set<char> ops = {'+','-','*','/'};
19     bool int_or_double = true; //true代表表达式中只有int
20     if(preex.find('.') != string::npos) {
21         int_or_double = false;
22     }
23     stack<int> int_stack;
24     stack<double> double_stack;
25     for(int i = ex_size-1;i>=0;i--) {
26         if(preex[i] == ' ') {
27             continue;
28         }
29         if(preex[i]>='0'&&preex[i]<='9') {
30             stringstream tmp;
31             stack<char> tmp_stack;
32             tmp_stack.push(preex[i]);
33             for(int j=i-1;j>=0;--j) {
34                 if((preex[j]>='0'&&preex[j]<='9') || preex[j]=='.') {
35                     tmp_stack.push(preex[j]);
36                     i--;
37                 }
38                 else if(preex[j] == ' ') {
39                     break;
40                 }
41             }
42             while(!tmp_stack.empty()) {
43                 tmp<<tmp_stack.top();
44                 tmp_stack.pop();
45             }
46             string str_tmp = tmp.str();
47             if(int_or_double) {
48                 int num;
49                 tmp>>num;
50                 int_stack.push(num);
51             }
52             else{
53                 double num;
54                 tmp>>num;
55                 double_stack.push(num);
56             }
57         }
58         else{ //如果是运算符
59             if(int_or_double) {
60                 int a = int_stack.top();
61                 int_stack.pop();
62                 int b = int_stack.top();
63                 int_stack.pop();
64                 int res = cal(a,b,preex[i]);
65                 int_stack.push(res);
66             }
67             else {
68                 double a = double_stack.top();
69                 double_stack.pop();
70                 double b = double_stack.top();
71                 double_stack.pop();
72                 double res = cal(a,b,preex[i]);
73                 double_stack.push(res);
74             }
75         }
76     }
77     if(int_or_double) {
78         int result = int_stack.top();
79         cout<<"result:"<<result<<endl;
80     }
81     else {
82         double result = double_stack.top();
83         cout<<"result:"<<result<<endl;
84     }
85     return 1;
86 }
  1. 中缀转后缀

3.1 中缀转后缀

①按运算符优先级对所有的运算单位加括号

②将运算符移动到对应括号的后面

③去掉括号,得到前缀表达式

(1)表达式树

(2)栈

3.2 后缀表达式解析结算

①从左到右扫描表达式

②遇到数字,数字压栈,遇到运算符,取出栈顶两个数做运算:次顶 op 栈顶,结果入栈

③重复,直到表达式最右侧

  1. 表达式合法性判断

(1)括号的合法性

这里的括号表达式只有 { } [ ] ( ) ,暂不算数字和运算符,且输入的表达式字符串里面没有其他无效字符

bool expreIsOK()
{

    map<char,char> exmap = {{'}','{'},{']','['},{')','('}};
    stack<char> char_stack;
    string str;
    getline(cin,str);
    cout<<"Your expression:"<<str<<endl;
    string::iterator iter = str.begin();
    while(iter != str.end()) {
        if(exmap.find(*iter) != exmap.end()) { //如果是右括号
            if(char_stack.empty() || char_stack.top() != exmap[*iter]) {
                return false;
            }
            else {
                char_stack.pop();
            }
        }
        else { //如果是左括号
            char_stack.push(*iter);
        }
        ++iter;
    }
    if(char_stack.empty()) {
        return true;
    }
    else {
        return false;
    }
}

(2)运算符合法性

(3)运算数合法性

  1. 完整的解析计算中缀表达式

①检验合法性:包括括号的合法性和运算符的合法性、运算数合法性

括号合法性:括号成对出现且遵循数学规范

运算符合法性:比如不能有两个连续的运算符

运算数合法性:这里暂忽略大数。如果遇到小数,则运算数 3.14 5. 都是合法的,但 3.14. 不合法

②中缀转成前缀

③前缀解析计算

原文链接: https://www.cnblogs.com/taoXiang/p/12563477.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/194796

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午6:48
下一篇 2023年2月12日 下午6:48

相关推荐