C#实现中缀表达式转后缀表达式以及运算

思路

中缀表达式转后缀表达式

  1. 初始化两个栈,运算符栈s1和储存中间结果的栈s2
  2. 从左到右扫描中缀表达式
  3. 遇到数字则压入s2中
  4. 遇到运算符{
    – 1.如果s1为空,或栈顶运算符为左括号,则直接将此运算符压入s1
    – 2.若优先级比栈顶运算符高,也压入s1
    – 3.否则,将栈顶的运算符弹出并压入s2中,再次转到 4.1 与s1中新的栈顶运算符比较
    }
  5. 遇到括号
    {
    –1. 如果是左括号,则直接压入s1
    –2. 如果是右括号,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
    }
  6. 重复步骤2至5,直到表达式最右边
  7. 将s1中剩余的运算符依次弹出并压入s2
  8. 依次弹出s2的元素,结果的逆序即对应的后缀表达式。

计算后缀表达式

  1. 从左到右扫描表达式,遇到数字时,将数字压入栈中
  2. 遇到运算符时,弹出栈顶的两个数,用运算符对他们进行相应的运算并将结果入栈
  3. 重复上述过程,直到表达式最右端,得到的结果即后缀表达式的结果

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace InsufixToSuffix
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
             * 完成将一个中缀表达式转成后缀表达式的功能
             * 1. 目标 1+((2+3)*4)-5  => 1 2 3 + 4 * + 5 -
             * 2. 因为对 string 进行操作不方便,因此先将表达式转换成对应的list
             * 3.将得到的中缀表达式对应的 list 转换成 后缀表达式对应的list
             */

            string expression = "1+((2+3)*4)-5";
            List<string> infixExpression = ToInfixExpressionList(expression);
            List<string> parseSuffixExpression = ParseSuffixExpressionList(infixExpression);
            foreach (var item in parseSuffixExpression)
            {
                Console.Write(item + " ");
            }

            Console.WriteLine();

            Console.WriteLine($"Res = {Calculate(parseSuffixExpression)}");
        }

        //将中缀表达式转换成对应的 List
        static List<string> ToInfixExpressionList(string s)
        {
            //定义一个List,存放中缀表达式对应的内容
            List<string> ls = new List<string>();
            int i = 0;  //用于遍历 中缀表达式字符串
            string str; //用于对多位数的拼接
            char c;     //每遍历到一个字符,就放入c
            do
            {
                if (!char.IsDigit(c = s[i]))    //如果c不是数字,就加入ls
                {
                    ls.Add(c.ToString());
                    i++;    //i后移
                }
                else//如果是数字,需要考虑多位数
                {
                    str = "";   //先将str清空
                    while (i < s.Length && char.IsDigit(c = s[i]))
                    {
                        str += c;
                        i++;
                    }
                    ls.Add(str);
                }
            } while (i < s.Length);
            return ls;
        }

        //完成将一个中缀表达式转换成后缀表达式
        static List<string> ParseSuffixExpressionList(List<string> ls)
        {
            //定义两个栈
            Stack<string> s1 = new Stack<string>();
            //因为 s2 在整个转换操作中没有pop操作,而且最后还要逆序,因此使用 List
            List<string> s2 = new List<string>();

            //遍历 ls
            foreach (var item in ls)
            {
                Regex regex = new Regex("\\d+");
                //如果是一个数,则加入s2
                if (regex.Match(item).Length > 0)
                {
                    s2.Add(item);
                }
                else if (item.Equals("("))
                {
                    s1.Push(item);
                }
                else if (item.Equals(")"))
                {
                    //如果是右括号,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,并将这对括号丢弃
                    while (!s1.Peek().Equals("("))
                    {
                        s2.Add(s1.Pop());
                    }
                    s1.Pop();   //将 ( 弹出
                }
                else
                {
                    //当item 的 优先级小于或等于s1栈顶运算符,将s1栈顶的运算符弹出并加入到s2中,再次转到 4.1 与s1中新的栈顶运算符比较
                    while (s1.Count != 0 && SomeMethods.GetValue(s1.Peek()) >= SomeMethods.GetValue(item))
                    {
                        s2.Add(s1.Pop());
                    }
                    //还需要将 item 压入栈
                    s1.Push(item);
                }
            }

            //将s1中剩余的运算符依次弹出并加入s2
            while (s1.Count != 0)
            {
                s2.Add(s1.Pop());
            }

            return s2;  //因为时存放到 List,因此按顺序输出就是对应的后缀表达式对应的List
        }

        //计算逆波兰表达式
        static int Calculate(List<string> ls)
        {
            Regex regex = new Regex("\\d+");
            //创建栈
            Stack<string> stack = new Stack<string>();
            //遍历 list
            foreach (var item in ls)
            {
                //使用正则表达式来取出数
                if (regex.Match(item).Length > 0) //如果是数字,就压入栈中
                {
                    stack.Push(regex.Match(item).Value);
                }
                else    //不是数就弹出两个数字进行计算
                {
                    int num2 = int.Parse(stack.Pop());
                    int num1 = int.Parse(stack.Pop());
                    int res = 0;
                    if (item.Equals("+"))
                    {
                        res = num1 + num2;
                    }
                    else if (item.Equals("-"))
                    {
                        res = num1 - num2;
                    }
                    else if (item.Equals("*"))
                    {
                        res = num1 * num2;
                    }
                    else if (item.Equals("/"))
                    {
                        res = num1 / num2;
                    }
                    else
                    {
                        throw new Exception("表达式有误");
                    }
                    stack.Push(res.ToString());
                }
            }

            //最后留在stack中的数据就是运算结果
            return int.Parse(stack.Pop());
        }
    }


    class SomeMethods
    {
        private static int ADD = 1;
        private static int SUB = 1;
        private static int MUL = 2;
        private static int DIV = 2;

        //返回优先级
        public static int GetValue(string operation)
        {
            int res = 0;
            switch (operation)
            {
                case "+":
                    res = ADD;
                    break;
                case "-":
                    res = SUB;
                    break;
                case "*":
                    res = MUL;
                    break;
                case "/":
                    res = DIV;
                    break;
                default:
                    Console.WriteLine("不存在该运算符");
                    break;
            }
            return res;
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值