因工作需要对表达式求值,借机巩固下基础知识,使用两个栈,一个存放操作数,一个存放算符。
在表达式的开始和结尾分别放一个#,表示开始和结束。
算符栈初始的时候有一个#算符,如果是计算1+2,这里会有一个疑问,1入栈后,读到算符+,
(当前的算符)其优先级比 栈顶算符# 大,也就是栈顶算符优先级低,则需要把该算符入栈。
下一个算符是#,其优先级比栈顶算符+的小,栈顶算符优先级大,则将两个操作数出栈和栈顶算符出栈,进行运算。
如果计算表达式1+2+3*4。
1入栈后,读到算符+,
(当前的算符)其优先级比 栈顶算符# 大,也就是栈顶算符优先级低,则需要把该算符入栈。
下一个算符是+,其优先级和栈顶算符优先级相等,这里会有一个疑问,根据则将栈顶算符出栈,并去取下一个字符。(错误)
这里把栈顶的+出栈,当前算符+也没有入栈,栈顶算符变成了#。 +算符都没有了,可怎么办?
读取下一个字符是3,操作数里面有1 2 3
读取到*,比栈顶算符优先高,栈顶算符优先级低,则入栈。
读取最后一个算符#,栈顶算符优先级高,则进行计算:3*4 。
正确的运算过程是:
1入栈后,读到算符+,
(当前的算符)其优先级比 栈顶算符# 大,也就是栈顶算符优先级低,则需要把该算符入栈。
下一个算符是+,其优先级和栈顶算符优先级相等,根据运算法则,同级别时,先左后右。应该将栈顶算符和两个操作数取出,进行计算,然后将当前字符和运算结果入栈。
支持+-*/运算的代码:
public class ExpCaculate { Stack<int> optd = new Stack<int>(); Stack<char> optr = new Stack<char>(); public void run(string exp) { optr.Push('#'); Console.WriteLine("计算表达式:" + exp); for (int i = 0; i < exp.Length; i++) { char ch = exp[i]; // 识别0-9数字 if (IsNumer(ch)) { // 从表达式里面提取数字 StringBuilder d = new StringBuilder(); d.Append(ch); for (int j = i+1; j < exp.Length; j++) { if (IsNumer(exp[j])) { d.Append(exp[j]); i = j; } else { break; } } int t = int.Parse(d.ToString()); optd.Push(t); } else if (IsOptr(ch)) { switch (Percede(ch)) { case ">": //当前算符优先级高, 栈顶算符优先级低 optr.Push(ch); break; case "<": case "=": int a = optd.Pop(); int b = optd.Pop(); char theta = optr.Pop(); int r = Caclulae(a, b, theta); optd.Push(r); optr.Push(ch); break; default: break; } } }// end for optr.Pop(); while (optr.Count > 1&&optd.Count>1) { int a = optd.Pop(); int b = optd.Pop(); char theta = optr.Pop(); int r = Caclulae(a, b, theta); optd.Push(r); } if (optd.Count == 1) { Console.WriteLine("计算结果是:" + optd.Pop()); optr.Clear(); optd.Clear(); } else { Console.WriteLine("error :"); } } private int Caclulae(int a, int b, char theta) { switch (theta){ case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } return 0; } private string Percede(char ch) { if (optr.Count == 0) { return ""; } char top = optr.Peek(); switch (top) { case '+': case '-': if (ch == '*' || ch == '/') { return ">"; } else if (ch == '+' || ch == '-') { return "="; } else { return "<"; } case '*': case '/': if (ch == '*' || ch == '/') { return "="; } else if (ch == '+' || ch == '-') { return "<"; } else { return "<"; } case '#': if (ch == '#') { return "="; } else { return ">"; } } return "="; } private bool IsOptr(char ch) { return ch == '+' || ch == '-' || ch == '*' || ch == '/'|| ch == '#'; } public bool IsNumer(char ch) { return ch > 47 && ch < 58; } }