C#学习之逆波兰公式简单实现

来源:互联网 发布:2017淘宝可以买彩票吗 编辑:程序博客网 时间:2024/06/07 05:49

Stack<T>和Stack

Stack<T>和Stack则是后进先出的数据结构,通过Push和Pop法实现添加元素到队列的顶部和从队列的顶部移除元素。同样也提供了Peek方法、Count属性和ToArray方法。

栈的实践使用:逆波兰公式

表达式一般由操作数(Operand)、运算符(Operator)组成,例如算术表达式中,通常把运算符放在两个操作数的中间,
这称为中缀表达式(Infix Expression),如A+B。
波兰数学家Jan Lukasiewicz提出了另一种数学表示法,它有两种表示形式:
把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB;
把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expression)或后缀表达式(Suffix Expression),如AB+;
其中,逆波兰表达式在编译技术中有着普遍的应用。
 
算法:
一、 将中缀表达式转换成后缀表达式算法:
1、从左至右扫描一中缀表达式。
2、若读取的是操作数,则判断该操作数的类型,并将该操作数存入操作数堆栈
3、若读取的是运算符
  (1) 该运算符为左括号"(",则直接存入运算符堆栈。
  (2) 该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。
  (3) 该运算符为非括号运算符:
      (a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。
      (b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。
      (c) 若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈。
4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。
 
二、逆波兰表达式求值算法:

      对后缀表达式求值比直接对中缀表达式求值简单。在后缀表达式中,不需要括号,而且操作符的优先级也不再起作用了。您可以用如下算法对后缀表达式求值:

  1. 初始化一个空堆栈
  2. 从左到右读入后缀表达式
  3. 如果字符是一个操作数,把它压入堆栈。
  4. 如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。
  5. 到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,那么堆栈应该为空。

using System;using System.Collections.Generic;using System.Diagnostics;//System.Diagnostics命名空间 包含了能够与系统进程 事件日志 和性能计数器进行交互的类 //一般用于帮助诊断和调试应用程序 //查考链接 https://www.douban.com/note/220654090/namespace ConsoleAppTest{    class Program    {        //是否为数字        //判断是否为整数字符串        static bool isNumber(string message)        {            //判断是否为整数字符串            //是的话则将其转换为数字并将其设为out类型的输出值、返回true, 否则为false            int result = -1;   //result 定义为out 用来输出值            try            {                //当数字字符串的为是少于4时,以下三种都可以转换,任选一种                //如果位数超过4的话,请选用Convert.ToInt32() 和int.Parse()                //result = int.Parse(message);                //result = Convert.ToInt16(message);                result = Convert.ToInt32(message);                return true;            }            catch            {                return false;            }        }        //是否为操作符        static bool isOpertor(string c)        {            return c == "+" || c == "-" || c == "*" || c == "/" || c == "(" || c == ")";        }        //判断操作符优先级大小        static bool comparePriority(string op1, string op2)        {            return getPriorityValue(op1) > getPriorityValue(op2);        }        //获取操作符优先级        static int getPriorityValue(string c)        {            int priority;            switch (c)            {                case "+":                    priority = 1;                    break;                case "-":                    priority = 1;                    break;                case "*":                    priority = 2;                    break;                case "/":                    priority = 2;                    break;                default:                    priority = 0;                    break;            }            return priority;        }        //计算值        static int getOperand(string op, int num1, int num2)        {            int result = -1;            switch (op)            {                case "+":                    result = num1 + num2;                    break;                case "-":                    result = num1 - num2;                    break;                case "*":                    result = num1 * num2;                    break;                case "/":                    result = num1 / num2;                    break;            }            return result;        }        static Stack<string> changeExpression(List<string> beforeExps)        {            Stack<string> operand = new Stack<string>();//操作数            Stack<string> opertor = new Stack<string>();//操作符            //遍历中序表示            int length = beforeExps.Count;            //判断是否为操作数              for (int i = 0; i < length; i++)            {                string c = beforeExps[i];                if (isNumber(c))                {                    //操作数 存在操作数栈                    operand.Push(c);                }                else                {                    //为运算符                      //若运算符为"("直接存入到运算符栈中                     if (c == "(")                    {                        opertor.Push(c);                    }                    else if (c == ")")                    {                        //该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。 将"("出栈                          while (opertor.Peek() != "(")                        {                            string stringvalue = opertor.Pop();                            operand.Push(stringvalue);                        }                        opertor.Pop();                    }                    else                    {                        // 该运算符为非括号运算符:                        //考虑栈顶为空的情况                         if (opertor.Count <= 0)                        {                            opertor.Push(c);                            continue;                        }                        // (a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。                        ////符合为左括号 直接存入运算符                        if (opertor.Peek() == "(")                        {                            opertor.Push(c);                        }                        else                        {                            //(b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。                              if (comparePriority(c, opertor.Peek()))                            {                                opertor.Push(c);                            }                            else                            {                                // (c) 若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈。                                string stringvalue = opertor.Pop();                                operand.Push(stringvalue);                                opertor.Push(c);                            }                        }                    }                }            }            //4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。            while (opertor.Count > 0)            {                string stringvalue = opertor.Pop();                operand.Push(stringvalue);            }            //反转operand 获取正常的会缀表达式            Stack<string> resultSt = new Stack<string>();            while (operand.Count > 0)            {                string stringvalue = operand.Pop();                resultSt.Push(stringvalue);            }            return resultSt;        }                //转换string为list表        static List<string> changeStrToList(string str)        {            List<string> resultSt = new List<string>();            List<int> sortNum = new List<int>();            bool isConNum = false;            foreach(char c in str)            {                if (isOpertor(c.ToString()))                {                    if (isConNum && sortNum.Count > 0)                    {                        //添加数字                        int num = 0;                        for (int i = sortNum.Count -1 ; i >= 0; i--)                        {                            if (i == sortNum.Count - 1)                            {                                num = num + sortNum[i];                            }else{                                num = num + sortNum[i] * 10 * (sortNum.Count - 1 - i );                            }                                                   }                        resultSt.Add(num.ToString());                        sortNum.Clear();                    }                    isConNum = false;                    //如果是操作符直接添加                    resultSt.Add(c.ToString());                }else{                    //如果是数字                    isConNum = true;                    sortNum.Add(int.Parse(c.ToString()));                }            }            if (sortNum.Count > 0)            {                //添加数字                int num = 0;                for (int i = sortNum.Count - 1; i >= 0; i--)                {                    if (i == sortNum.Count - 1)                    {                        num = num + sortNum[i];                    }                    else                    {                        num = num + sortNum[i] * 10 * (sortNum.Count - 1 - i);                    }                }                resultSt.Add(num.ToString());                sortNum.Clear();            }            return resultSt;        }        //计算逆波兰公式        static int calculateExpression(Stack<string> st)        {            //临时存储计算数据            Stack<string> reslutSt = new Stack<string>();            while(st.Count > 0)            {                string numStr = st.Peek();                if (isNumber(numStr))                {                    //如果字符是一个操作数,把它压入堆栈。                    reslutSt.Push(numStr);                }                else                {                    //如果字符是个操作符,弹出两个操作数,执行恰当操作,                    //然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。                     int number1 = int.Parse(reslutSt.Pop());                    int number2 = int.Parse(reslutSt.Pop());                    int value = getOperand(numStr, number2, number1);                    reslutSt.Push(value.ToString());                }                st.Pop();            }            return int.Parse(reslutSt.Peek());        }        static void Main(string[] args)        {            Console.WriteLine("C# 逆波兰公式 输入您要计算的公式,按enter结束");            //string inputStr = Console.ReadLine();            string teststr = Console.ReadLine();            List<string> inputStr = changeStrToList(teststr);            Console.WriteLine("公式为:");            foreach (string str in inputStr)            {                Console.Write("{0} ", str);            }            Console.Write(" ===> ");            Stack<string> changeSt = changeExpression(inputStr);            foreach (string str in changeSt)            {                Console.Write("{0} ", str);            }            Console.WriteLine("逆波兰公式计算:");            //计算公式的值            int resultValue = calculateExpression(changeSt);            Console.WriteLine("{0} = {1} ", teststr ,resultValue);            Console.ReadKey();        }    }}


0 0
原创粉丝点击