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. 不合法
②中綴轉成前綴
③前綴解析計算