【栈】栈的应用-四则运算表达式求值

背景

大话数据结构4.9栈的应用——四则运算表达式求值,动手实践。

步骤

1.将中缀表达式转换为后缀表达式(参考 中缀表达式转换为后缀表达式

  • 定义

标准四则运算表达式叫做中缀表达式,特点是运算符号都在

  • 规则
  1. 从左到右遍历表达式的每个数字和符号
  2. 若是数字就输出
  3. 若是符号,判断该符号与栈顶符号的优先级。

当前符号优先级 栈顶符号时, 进栈。

当前符号优先级 <= 栈顶符号,栈顶元素依次出栈、输出,当前符号进栈。

当前符号是右括号,栈顶元素依次出栈并输出,直到遇到左括号停止,左括号弹出但不输出。

2.使用后缀表达式进行运算,得出结果

  • 规则
  1. 从左到右遍历表达式的每个数字和符号
  2. 遇到数字就进栈,遇到符号就将处于栈顶的两个数字出栈运算,运算结果进栈。

代码

ExpressionsHelper.cs文件

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

namespace DataStructure
{
    /// <summary>
    /// 栈的应用-计算四则表达式
    /// 1、将中缀表达式转换成后缀表达式
    /// 2、使用后缀表达式进行运算,得出结果
    /// </summary>
    class ExpressionsHelper
    {
        private static int GetPriority(string op)
        {
            switch (op)
            {
                case "+":
                case "-":
                    return 1;
                case "*":
                case "/":
                    return 2;
                case "":
                    return 3;
            }
            return -1;
        }

        /// <summary>
        /// 将中缀表达式转换成后缀表达式
        /// 标准四则运算表达式->中缀表达式:所有运算负号都在两数字中间
        /// 1、从左到右遍历中缀表达式的每个数字和符号
        /// 2、是数字就输出,是符号则判断与栈顶符号的优先级,
        /// 3、当前符号优先级<=栈顶符号或者当前符号是右括号,栈顶元素依次出栈,将当前符号进栈
        /// 4、遇到右括号才弹出左括号
        /// 测试用例:9 + ( 3 - 1 ) * 3 + 10 / 2 期望结果:9 3 1 - 3 * + 10 2 / +
        /// 测试用例:1 + 2 * 3 + ( 4 * 5 + 6 ) * 7 期望结果:1 2 3 * + 4 5 * 6 + 7 * +
        /// 测试用例:10*(0.8+0.2) 期望结果:10 0.8 0.2 + *
        /// </summary>
        public static string GetPostfixExpression(string infixExpression)
        {
            Stack<string> tmpStack = new Stack<string>();
            List<string> resultList = new List<string>();
            List<string> tmp = new List<string>();
            //提取+-*/数字和括号
            foreach (Match match in Regex.Matches(infixExpression, @"([+\-*/\(\)])|(\d+(\.\d+)?)"))
                tmp.Add(match.Value);

            foreach (var item in tmp)
            {
                if (item == "")
                {
                    continue;
                }
                if (IsNumberic(item))//数字输出
                {
                    resultList.Add(item);
                }
                else if (item == "(")
                {
                    tmpStack.Push(item);
                }
                else if (item == ")")
                {
                    while (tmpStack.Count > 0 && tmpStack.Peek() != "(")
                    {
                        var top = tmpStack.Pop();
                        resultList.Add(top);
                    }
                    //只有遇到右括号的时候左括号才会弹出
                    if (tmpStack.Count > 0 && tmpStack.Peek() == "(")
                    {
                        tmpStack.Pop();
                    }
                }
                else
                {
                    //优先级:当前<=栈顶,当前符号优先级低于或等于栈顶符号,栈顶元素依次出栈,将当前符号进栈,遇到左扩号停止弹出行为。
                    while (tmpStack.Count > 0 && GetPriority(item) <= GetPriority(tmpStack.Peek()))
                    {
                        var top = tmpStack.Pop();
                        resultList.Add(top);
                    }
                    tmpStack.Push(item);
                }
            }

            //数据已经读到末尾,栈中符号直接弹出并输出
            while (tmpStack.Count != 0)
            {
                var top = tmpStack.Pop();
                resultList.Add(top);
            }
            //空格分隔
            var result = string.Join(" ", resultList);
            Console.WriteLine($"中缀表达式:{infixExpression}");
            Console.WriteLine($"后缀表达式:{result}");
            return result;
        }

        /// <summary>
        /// 使用后缀表达式进行运算,得出结果(每个输入都要用空格分隔)
        /// 规则
        /// 1、从左到右遍历表达式的每个数字和符号
        /// 2、遇到数字就进栈,遇到符号就将处于栈顶的两个数字出栈运算,运算结果进栈。
        /// </summary>
        public static float GetPostfixExpressionResult(string postfixExpression)
        {
            Stack<float> tmpStack = new Stack<float>();
            string[] tmp = Regex.Split(postfixExpression, "\\s+", RegexOptions.IgnoreCase);

            foreach (var item in tmp)
            {
                if (IsNumberic(item))
                {
                    if (int.TryParse(item, out int intItem))
                    {
                        tmpStack.Push(intItem);
                    }
                    else if (float.TryParse(item, out float floatItem))
                    {
                        tmpStack.Push(floatItem);
                    }
                }
                else
                {
                    var b = tmpStack.Pop();
                    var a = tmpStack.Pop();
                    var tmpResult = GetResult(a, item, b);
                    tmpStack.Push(tmpResult);
                }
            }
            var result = tmpStack.Pop();
            if (tmpStack.Count > 0)
            {
                throw new Exception("后缀表达式错误");
            }
            Console.WriteLine($"运算结果:{result}");
            return result;
        }

        /// <summary>
        /// 计算中缀表达式
        /// </summary>
        public static float Calc(string infixExpression)
        {
            var postfixExpression = GetPostfixExpression(infixExpression);
            var result = GetPostfixExpressionResult(postfixExpression);
            return result;
        }

        private static float GetResult(float a, string symbol, float b)
        {
            float result = 0;
            switch (symbol)
            {
                case "+":
                    result = a + b;
                    break;
                case "-":
                    result = a - b;
                    break;
                case "*":
                    result = a * b;
                    break;
                case "/":
                    result = a / b;
                    break;
                default:
                    break;
            }
            return result;
        }

        /// <summary>
        /// 判断是否数字
        /// </summary>
        public static bool IsNumberic(string num)
        {
            string pattern = @"\d+(\.\d+)?"; //匹配整数和浮点数
            bool result = Regex.IsMatch(num, pattern);
            return result;
        }
    }
}

Program.cs文件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataStructure
{
    class Program
    {
        static void Main(string[] args)
        {
            #region 栈的应用 - 计算四则表达式(整数公式)

            var v1 = ExpressionsHelper.Calc("9+(3-1)*3+10/2");
            Console.WriteLine();

            var v2 = ExpressionsHelper.Calc("1+2*3+(4*5+6)*7");
            Console.WriteLine();

            #endregion

            #region 栈的应用 - 计算四则表达式(浮点数公式)

            var v3 = ExpressionsHelper.Calc("10*(0.8+0.2)");
            Console.WriteLine();

            var v4 = ExpressionsHelper.Calc("10*(8+2)");
            Console.WriteLine();

            #endregion
        }
    }
}

结果

完整项目

https://github.com/LJLCarrien/DataStructure

后续

上面贴的代码已更新,在原来的基础上,支持浮点数表达式运算;

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值