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


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


你可能感兴趣的:(C#学习之逆波兰公式简单实现)