解析表達式---C++實現


 

1. 中綴、前綴、后綴表達式

  對於一個人可識別的表達式:1+(2+3)*4-5

  根據操作符的位置不同分為:

    ①中綴表達式:1+(2+3)*4-5

    ②前綴表達式:- + 1 * + 2 3 4 5  

    ③后綴表達式:1 2 3 + 4 * + 5 -

  前綴表達式和后綴表達式里面已經包含了計算順序,因此不需要括號來確定優先級

2. 中綴轉前綴

  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 }

 

3. 中綴轉后綴

  3.1 中綴轉后綴  

  ①按運算符優先級對所有的運算單位加括號

  ②將運算符移動到對應括號的后面

  ③去掉括號,得到前綴表達式

(1)表達式樹

(2)棧

 

  3.2 后綴表達式解析結算 

  ①從左到右掃描表達式

  ②遇到數字,數字壓棧,遇到運算符,取出棧頂兩個數做運算:次頂 op 棧頂,結果入棧

  ③重復,直到表達式最右側

4. 表達式合法性判斷

(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)運算數合法性

 

 

5. 完整的解析計算中綴表達式

  ①檢驗合法性:包括括號的合法性和運算符的合法性、運算數合法性

    括號合法性:括號成對出現且遵循數學規范

    運算符合法性:比如不能有兩個連續的運算符

    運算數合法性:這里暫忽略大數。如果遇到小數,則運算數 3.14  5. 都是合法的,但 3.14. 不合法

  ②中綴轉成前綴

  ③前綴解析計算

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM