C#数学表达式计算(中缀转换后缀)数据结构 括号 四则运算 幂运算 取模 三角函数
2018-10-12 20:21
639 查看
前言:
1.遇到操作数,直接输出;
2.栈为空时,遇到运算符,入栈;
3.遇到左括号,将其入栈;
4.遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出; (左括号丢弃 不输出)
5.遇到其他运算符 + - * / 时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;
6.最终将栈中的元素依次出栈,输出。
全文地址请点击:https://blog.csdn.net/qq_34992845/article/details/70313588?utm_source=copy
后缀表达式的计算:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
如何区分负号与减号
如果“-”是第一个字符时{
在前面加上“0-”
}
否则{
如果“-”前一个字符是数字 “-”是减号
如果“-”前一个字符是“^”幂运算符 “-”是负号
否则在前面加上“0-”
}
如-1-(-4^2)
会转换成0-1-(0-4^2)来处理
三角函数的运算思路(这里用的是角度制)
输入式子->转换成小写->转换成运算符->计算
如输入Sin(30)
转换成小写sin(30)
转换成运算符s(30)
运算0.5
代码:
若有不正之处,请多多谅解并欢迎指正。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 计算表达式 { class Program { static void 错误检测(string s,double d) { double a= Calculation(s); Console.WriteLine(string.Format("{0} 计算结果{1} 正确结果{2} ",s,a,d)); } static void Main(string[] args) { /* 容易出错的式子: -2*(5-2)=-6 -2*(-2)=4 1-(-4^2)=17 1+(-4^-2)=0.9375 1+(-4)^-2=1.0625 */ 错误检测("-2 * (5 - 2)" ,-6); 错误检测("-2*(-2)" , 4); 错误检测("-64*(-4)^(-2)" , -4); 错误检测("1-(-4^2)" , 17); 错误检测("-1+(-4^-2)" , -1.0625); 错误检测("1+(-4)^-2" , 1.0625); 错误检测("Sin(90)", 1); 错误检测("1-4*Sin(-1*(-2^5+2))", -1); 错误检测("8*sin(-1*(-2^5+2))^2", 2); 错误检测("cos60*4", 2); 错误检测("tan(44+1)", 1); Console.WriteLine(string.Format("{0} 计算结果{1} 正确结果{2} ", "tan(90)", Calculation("tan(90)"), "不存在的")); //Console.WriteLine(Calculation("S(-30)")); } public static double Calculation(string str)//函数已封装好 用到的时候直接调用该方法ok { //Console.WriteLine("中缀表达式:"+str); str=str.ToLower();//把字符串转换成小写 RemoveSpaces(ref str); StrPreprocessing(ref str); //Console.WriteLine("中缀表达式:" + str + " 预处理"); List<object> list = ToPostfix(str); //转换成中缀表达式 return CalculationPostfix(list); } static double CalculationPostfix(List<object>list)//计算后缀表达式 { List<double> stacks = new List<double>(); //计算后缀表达式 for (int i = 0; i < list.Count; i++) { if (list[i] is double) { stacks.Add((double)list[i]); } else { string c = (string)list[i]; double aa, bb; switch (c) { case "s": aa = stacks.Last(); stacks.RemoveAt(stacks.Count - 1); stacks.Add(Math.Sin(aa*Math.PI/180));//这里用的是角度制 弧度制的话改成Math.Sin(aa)就行了 break; case "c": aa = stacks.Last(); stacks.RemoveAt(stacks.Count - 1); stacks.Add(Math.Cos(aa * Math.PI / 180)); break; case "t": aa = stacks.Last(); stacks.RemoveAt(stacks.Count - 1); stacks.Add(Math.Tan(aa * Math.PI / 180)); break; default: bb = stacks.Last(); stacks.RemoveAt(stacks.Count - 1); aa = stacks.Last(); stacks.RemoveAt(stacks.Count - 1); stacks.Add(Operation(aa, bb, c)); break; } } } return stacks[0];//返回计算结果 } static List<object> ToPostfix(string infix)//转换成后缀表达式 { List<object> list = new List<object>();//一个集合 List<string> stacks = new List<string>();//用来存符号的栈 int len = infix.Length; int a = 0, b = 0; for (int i = 0; i < len; i++) { //该for循环作用是 把字符串的数字括号运算符区分开来并添加到集合list string c = infix.Substring(i, 1); if (IsNum(c)) { b++; if (i == len - 1) list.Add(ParseNum(infix.Substring(a, b))); } else { string sum = infix.Substring(a, b); if (sum.Length != 0) list.Add(ParseNum(sum)); a = i + 1; b = 0; } switch (c) //符号栈操作 { case "(": stacks.Add(c); break; case ")": while (stacks.Count > 0) { if (stacks.Last() != "(") { list.Add(stacks.Last()); stacks.RemoveAt(stacks.Count - 1); } else { stacks.RemoveAt(stacks.Count - 1); break; } } break; case "+": case "-": case "*": case "/": case "%": case "^": case "s": case "c": case "t": while (stacks.Count > 0) { if (Priority(c, stacks.Last())) { list.Add(stacks.Last()); stacks.RemoveAt(stacks.Count - 1); } else break; } stacks.Add(c); break; } } while (stacks.Count > 0) //最后的出栈 { list.Add(stacks.Last()); stacks.RemoveAt(stacks.Count - 1); } //Console.Write("后缀表达式:"); //for (int i = 0; i < list.Count; i++) Console.Write(list[i]); return list; } static void StrPreprocessing(ref string infix)//字符串预处理 { int len = infix.Length; StringBuilder str = new StringBuilder(); //把sin cos tan分别改为s c t方便后面的运算 while (infix.IndexOf("sin") >=0 || infix.IndexOf("cos") >=0 || infix.IndexOf("tan") >=0) { int a = infix.IndexOf("sin"); if(a!=-1) infix=infix.Remove(a+1,2); a = infix.IndexOf("cos"); if (a != -1) infix=infix.Remove(a + 1, 2); a = infix.IndexOf("tan"); if (a != -1) infix=infix.Remove(a + 1, 2); } len = infix.Length; str = new StringBuilder(); for (int i = 0; i < len; i++) { string c = infix.Substring(i, 1); if (c == "-") { if (i == 0) { str.Append("0-"); } else { string cc = infix.Substring(i - 1, 1); if (IsNum(cc)) { str.Append(c); } else if (cc == "^") { //避免2^-2=0.25转换成2^0-2=-1 str.Append("_"); } else { // str+="_"; str.Append("0-"); } } } else str.Append(c); } infix = str.ToString(); } static void RemoveSpaces(ref string infix)//删除空格 { int len = infix.Length; StringBuilder str = new StringBuilder();//https://blog.csdn.net/qq_28187979/article/details/76607253 //删除空格 for (int i = 0; i < len; i++) { string c = infix.Substring(i, 1); if (c == " ") continue; str.Append(c); } infix = str.ToString(); } static double Operation(double a,double b,object c)//运算 { switch (c) { case "+": return a + b; case "-": return a - b; case "*": return a * b; case "/": return a / b; case "%": return a % b; case "^": return Math.Pow(a, b); } throw new Exception(); } static bool Priority(string a,string b)//优先级判断 { //true为a优低于b if (Grade(a) <= Grade(b)) return true; return false; } static int Grade(string s)//返回该运算符的等级 { switch (s) { case "(": return 0; case "-": case "+": return 1; case "/": case "*": case "%": return 2; case "^": return 3; case "s": case "c": case "t": return 4; case ")": return 5; } return -1; } static bool IsNum(string s)//传入一个字符 判断该字符是不是数字。负号和点也属于数字 -3.14 { switch (s) { case "_"://预处理之后负号(-)转换成_ 减号-不变 case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": case ".": return true; } return false; } static bool IsSymbol(object s)//传入一个字符 判断该字符是不是符号 { switch (s) { case "+": case "-": case "*": case "/": case "%": case "^": case "s": case "c": case "t": return true; } return false; } static double ParseNum(string num)//string转换double 在double.Parse(str);的基础上处理 { if (num.Length > 0) { if (num.Substring(0, 1) == "_") return -double.Parse(num.Substring(1, num.Length - 1)); else return double.Parse(num.Substring(0, num.Length)); } throw new Exception(); } } }阅读更多
相关文章推荐
- 【数据结构】用栈实现的简单计算器(先转换为后缀表达式、可以计算带括号的)
- 中缀表达式的计算(只包含四则运算与括号)
- 【数据结构】栈的应用---四则运算表达式求值(中缀表达式与后缀表达式转换)
- 中缀/后缀表达式转换-使用四则混合运算表达式生成树
- 中缀/后缀表达式转换-使用四则混合运算表达式生成树
- java中正则表达式用Pattern计算字符串的结果(四则运算);分成有括号和没括号;当然也可以采用逆波兰式
- C#将字符串转换成运算表达式并得到计算结果
- PTA 表达式转换 算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。
- 【原创】Delphi实现数学表达式的计算(逆波兰式法)-四则运算解析
- 四则运算之中缀表达式转后缀表达式
- 表达式计算 四则运算(有括号)的计算
- 堆栈的应用(2) 中缀算术表达式到后缀(逆波兰记法reverse polish notation)的转换及其计算 C++实现
- 计算带括号的四则运算表达式
- 计算表达式的值(仅含有四则运算和支持括号嵌套,浮点数运算)
- 中缀计算四则运算表达式
- 数据结构之栈(中缀转后缀计算四则运算)
- 中缀表达式转换为后缀表达式,计算后缀表达式
- 栈的应用:中缀和后缀表达式的转换及计算
- 中后缀表达式的相互转换和四则运算表达式求值
- 堆栈的应用(2) 中缀算术表达式到后缀(逆波兰记法reverse polish notation)的转换及其计算 C++实现