C#中缀表达式实现带浮点优先级的计算器

先来个运行截图吧:


老师要求用c#写个计算器,虽然写了无数遍了(用c写,c++写,java写...),于是这次决定用逆波兰撸个新鲜的计算器,和原先我那个java用递归方法写的相比,这里实在是让代码简洁了许多许多,而且浮点运算,正负号都可以支持,果然还是体现了数据结构的美丽和强大


先写两个栈:

namespace Utils_Calculate
{
    public class Static_Double {
        private double[] opnd = new double[500];
        private int cur = -1;
        public void Push(double p){
            if (cur < 500) opnd[++cur] = p;
        }

        public bool IsEmpty(){
            return cur < 0 ? true : false;
        }

        public double Pop() {
            if (cur >= 0) return opnd[cur--];
            else return 0;
        }

        public void clear(){
            cur = -1;
        }
        
    }
    public class Static_Char {
        private char[] optr = new char[500];
        private int cur = -1;
        public void Push(char c){
            if (cur < 500) optr[++cur] = c;
        }

        public bool IsEmpty(){
            return cur < 0 ? true : false;
        }

        public char Pop(){
            if (cur >= 0) return optr[cur--];
            else return '\n';
        }
        public void clear(){
            cur = -1;
        }
    }
}


具体代码如下:

namespace Utils_Calculate
{
    class CharUtil {
       public static bool IsDigit(char c){
            return (c >= 48 && c <= 57 || c == '.') ? true : false;
        }
    }

   public class Rpn_Calculate: IRpn_Calculate
    {
        //定义优先级,即当前所指运算符优先级为0,栈顶元素优先级为-1
        private int cur_pri = 0, top_pri = -1;
        //数据栈
        Static_Double opnd = new Static_Double();
        //符号栈
        Static_Char optr = new Static_Char();
        //优先级定义
        private int GetPRI(char c){
            if (c == '+' || c == '-') return 1;
            if (c == '*' || c == '/') return 2;
            if (c == '(' || c == ')') return 0;
            return -1;
        }

        //计算函数
        private double Cal(double before,char mark,double after){
            if (mark == '+') return before + after;
            if (mark == '-') return before - after;
            if (mark == '*') return before * after;
            if (mark == '/') return before / after;
            throw new System.Exception();
        }
        //逆波兰计算
        public double Rnp(char[] str,int len){
            
            try
            {
                for (int i = 0; i < len; i++){
                     string x = "";double read_x = 0;char c = ' ';
                    //如果c是数字或小数点
                    if (CharUtil.IsDigit(c=str[i])){
                        x += c;
                        //循环读数包括小数点(比如8.88+7.777,这里会分三次读,第一次循环读入8.88,第二次读入+,第三次循环读入7.777)
                    while (i < len-1&& CharUtil.IsDigit(c = str[++i]))
                            x += c;
                        read_x = double.Parse(x);
                        //读出的数据入数据栈
                        opnd.Push(read_x);
                    }
                    //如果c是运算符,并且c的优先级高于栈顶符号的优先级,则c入栈
                    if ((cur_pri = GetPRI(c)) >= 0) {
                            if (c=='('|| cur_pri > top_pri){
                            top_pri = cur_pri;
                            optr.Push(c);
                            //如果c是')',则符号栈的元素不断出桟、运算,直到遇到左括号
                        }else if (c == ')'){
                            char _c =' '; double result = 0;
                            while ((_c=optr.Pop())!='('){
                                double after = opnd.Pop();
                                result = opnd.Pop();
                                result = Cal(result, _c,after);
                                opnd.Push(result);
                            }
                            //栈顶优先级更新
                            if (optr.IsEmpty())top_pri = -1;
                            else{
                            char char_top = optr.Pop();
                            top_pri = GetPRI(char_top);
                            optr.Push(char_top);
                            }
                        }else{
                            //当前运算符优先级低于栈顶,先出栈计算(运算符出桟一个,数据栈出桟两个),再将当前运算符入栈
                            opnd.Push(Stack_Cal(optr.Pop()));
                            optr.Push(c);
                            top_pri = GetPRI(c);
                        }
                    }
                }
                double final_result = 0;
                //最后结束的时候两个栈里面的优先级是有序的,需要出桟计算一波
                while (!optr.IsEmpty()){
                    char _c = optr.Pop();
                    double after = opnd.Pop();
                    final_result = opnd.Pop();
                    final_result = Cal(final_result, _c, after);
                    opnd.Push(final_result);
                }
                //返回结果
                double _result=opnd.Pop();
                Reset();
                return _result;
            }
            catch (System.Exception){
                throw new System.Exception("请不要乱输谢谢..");
            }
        }

        //还原配置
       private void Reset() { cur_pri = 0; top_pri = -1; opnd.clear();optr.clear(); }

        //出栈计算(运算符出桟一个,数据栈出桟两个)
        private double Stack_Cal(char mark){
            double after = opnd.Pop();
            double before = opnd.Pop();
            return Cal(before, mark, after);
        }

    }
}

    class Program
    {
        static void Main(string[] args)
        {  
            //测试代码:
            Rpn_Calculate calculator = new Rpn_Calculate();
            const string test = "1+2*(3-4)/5.5";
            double result = calculator.Rnp(test.ToCharArray(), test.Length);
            Console.WriteLine(result);
            Console.ReadKey();
        }
    }


做个UI界面也是个不错的想法:


猜你喜欢

转载自blog.csdn.net/qq_37960007/article/details/79885878
今日推荐