C#数学表达式计算(中缀转换后缀)数据结构 括号 四则运算 幂运算 取模 三角函数

前言:

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
C#数学表达式计算(中缀转换后缀)数据结构 括号 四则运算 幂运算 取模 三角函数

代码:

若有不正之处,请多多谅解并欢迎指正。

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();
        }
    }
}