关于逆波兰式
一个表达式E的逆波兰式如下定义:
- 如果E是一个变量或者常量,E的后缀式是其自身;
- 如果E是E1 op E2的形式,则其后缀式是E1' E2' op的形式,其中E1'表示E1的后缀式;
- 如果E=(E1),那么E的后缀式与E1相同(换言之,逆波兰式不需要括号来表示优先级);
将一个普通的中缀表达式exp转换为逆序表达式的一般算法是:
stack s1,s2; //s1是临时存放运算符的,s2是存放后缀式的
s1.push('#'); //放入优先级最低的符号
for x in exp:
if(x is num):
y=got(x); //注意这里got函数里面必须完成x迭代器的前行
s2.push(y);
else if(x is op):
while(x<=s1.top() || s1.top=='('):
s2.push(s1.pop());
if(x==')'):
while(s1.top()!='(')s2.push(s1.pop());
s1.pop();
else s1.push(x);
while(s1.top()!='#')s2.push(s1.pop());
完成上述步骤后,s2中存放的即是倒序的逆波兰式;
利用逆波兰式posfix计算:
stack s;
doubel lhs,rhs=s.top();
for x in posfix:
if(x is op):
rhs=s.pop();
lhs=s.pop();
rhs=calc(lhs,rhs,x);
s.push(rhs);
else s.push(x)
return rhs;
如果需要计算浮点数,最好将操作符映射成小浮点数;
无bug的解决方案是先分词,然后用stack存放单词结构,无须映射,更加清晰;
补上例程:
View Code
1 #include <vector> 2 #include <map> 3 #include <stack> 4 #include <iostream> 5 #include <sstream> 6 #include <string> 7 #include <cctype> 8 using namespace std; 9 10 struct Word 11 { 12 Word(char k='n',double v=0): 13 kind(k),value(v) 14 { 15 16 } 17 char kind; 18 double value; 19 }; 20 bool isOperator(char k) 21 { 22 static char op[]= 23 { 24 '+','-','*','/','(',')' 25 }; 26 int size=sizeof(op)/sizeof(op[0]); 27 for(int i=0;i!=size;++i) 28 { 29 if (k==op[i]) 30 { 31 return true; 32 } 33 } 34 return false; 35 } 36 int split2Words(const string& srcString,vector<Word> &dst) 37 { 38 dst.clear(); 39 stringstream ss; 40 ss<<srcString; 41 char kindFlag; 42 double value; 43 while (ss>>kindFlag) 44 { 45 if(isdigit(kindFlag)) 46 { 47 ss.putback(kindFlag); 48 ss>>value; 49 dst.push_back(Word('n',value)); 50 }else if(isOperator(kindFlag)) 51 { 52 dst.push_back(Word(kindFlag)); 53 } 54 else 55 { 56 return -1; 57 } 58 } 59 return 0; 60 } 61 int convert2Posfix(vector<Word> &words) 62 { 63 stack<Word> s1,s2; 64 s1.push('#'); 65 static map<char,char> priority; 66 if (priority.empty()) 67 { 68 priority['#']=0; 69 priority['+']=2; 70 priority['-']=2; 71 priority['*']=3; 72 priority['/']=3; 73 priority['(']=4; 74 priority[')']=4; 75 } 76 Word current; 77 for(int i=0;i!=words.size();++i) 78 { 79 current=words[i]; 80 if (current.kind=='n') 81 { 82 s2.push(current); 83 }else 84 { 85 while(priority[current.kind]<=priority[s1.top().kind] && s1.top().kind!='(') 86 { 87 s2.push(s1.top()); 88 s1.pop(); 89 } 90 if (current.kind==')') 91 { 92 while(s1.top().kind!='(') 93 { 94 s2.push(s1.top()); 95 s1.pop(); 96 } 97 s1.pop(); 98 }else 99 { 100 s1.push(current); 101 } 102 } 103 } 104 while(s1.top().kind!='#') 105 { 106 s2.push(s1.top()); 107 s1.pop(); 108 } 109 words.clear(); 110 while (!s2.empty()) 111 { 112 words.insert(words.begin(),s2.top()); 113 s2.pop(); 114 } 115 //for (int i=0;i!=words.size();++i) 116 //{ 117 // if (words[i].kind=='n') 118 // { 119 // cout<<words[i].value; 120 // }else 121 // { 122 // cout<<words[i].kind; 123 // } 124 //} 125 //cout<<endl; 126 return 0; 127 } 128 double calc(double lhs,double rhs,char op) 129 { 130 switch (op) 131 { 132 case '+': 133 return lhs+rhs; 134 case '-': 135 return lhs-rhs; 136 case '*': 137 return lhs*rhs; 138 case '/': 139 return lhs/rhs; 140 default: 141 break; 142 } 143 return 0; 144 } 145 double calcPosix(const vector<Word> &words) 146 { 147 stack<double> s1; 148 double lhs,rhs=words[0].value; 149 for(int i=0;i!=words.size();++i) 150 { 151 if (words[i].kind=='n') 152 { 153 s1.push(words[i].value); 154 }else 155 { 156 rhs=s1.top(); 157 s1.pop(); 158 lhs=s1.top(); 159 s1.pop(); 160 rhs=calc(lhs,rhs,words[i].kind); 161 s1.push(rhs); 162 } 163 } 164 return rhs; 165 } 166 int main() 167 { 168 string expression; 169 vector<Word> words; 170 double result; 171 while(getline(cin,expression)) 172 { 173 int flag=split2Words(expression,words); 174 //if(flag<0) exit(EXIT_FAILTURE); 175 convert2Posfix(words); 176 result=calcPosix(words); 177 cout<<result<<endl; 178 } 179 180 return 0; 181 }
上述例程可以计算含括号的浮点数普通四则运算,但是没有错误处理功能…
程序待优化。