C#使用递归和堆栈计算含有小括号,加减乘除的表达式(1)

14 篇文章 0 订阅

比如表达式 1+2+7*(12.3-(12+9)/3)-(1.1+6.6)+4*5.2

计算出该结果。

实现思路:

1.查找小括号,然后依次消去所有的小括号,此时表达式没有小括号
2.进行乘除运算
3.最后进行加减运算

新建窗体应用程序CalculateUseStackAndRecursionDemo,

将默认的Form1重命名为FormCalculate,窗体 FormCalculate设计器如下:

新建枚举类文件OperatorSymbol.cs,枚举OperatorSymbol源程序如下:

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

namespace CalculateUseStackAndRecursionDemo
{
    /// <summary>
    /// 运算符号,只考虑 加减乘除
    /// </summary>
    enum OperatorSymbol : ushort
    {
        /// <summary>
        /// 乘,ASCII为42
        /// </summary>
        Multiply = '*',
        /// <summary>
        /// 除,ASCII为47
        /// </summary>
        Divide = '/',
        /// <summary>
        /// 加,ASCII为43
        /// </summary>
        Addition = '+',
        /// <summary>
        /// 减,ASCII为45
        /// </summary>
        Subtract = '-'
    }
}

新建关键的类文件RecursionCalculateUtil.cs,主要的逻辑和流程代码都在这里。

类RecursionCalculateUtil源程序如下:

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

namespace CalculateUseStackAndRecursionDemo
{
    /// <summary>
    /// 使用递归,计算含有小括号,加减乘除的表达式
    /// 1.查找小括号,然后依次消去所有的小括号,此时表达式没有小括号
    /// 2.进行乘除运算
    /// 3.最后进行加减运算
    /// </summary>
    class RecursionCalculateUtil
    {
        /// <summary>
        /// 显示计算过程事件
        /// </summary>
        public static event Action<string> EventDisplayProcess;
        /// <summary>
        /// 含有小括号的四则运算,先计算小括号,再计算乘除,最后计算加减。
        /// 当表达式可以直接转化为浮点数时,递归终止
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static string GetExpression(string expression)
        {
            string subExpression = string.Empty;
            //找出第一个 右小括号
            int rightParenthesisIndex = expression.IndexOf(')');
            //找出与第一个右小括号对应的 左小括号
            int leftParenthesisIndex = -1;
            if (rightParenthesisIndex >= 0)
            {
                //存在右小括号,不存在左小括号【LastIndexOf:从指定索引开始,向左(向前)查找多少个】
                leftParenthesisIndex = expression.LastIndexOf('(', rightParenthesisIndex, rightParenthesisIndex);
                if (leftParenthesisIndex == -1)
                {
                    throw new Exception($"表达式【{expression}】非法,缺少开始左小括号"("");
                }
                //这里解析左右小括号之间的内容,比如:(3+5*6.2)
                string parseContent = expression.Substring(leftParenthesisIndex + 1, rightParenthesisIndex - leftParenthesisIndex - 1);
                subExpression = ArithmeticWithoutParenthesis(parseContent);
                subExpression = expression.Substring(0, leftParenthesisIndex) + subExpression + expression.Substring(rightParenthesisIndex + 1);
                EventDisplayProcess?.Invoke($"已消除一对小括号,源表达式【{expression}】,简化后结果【{subExpression}】");
                //继续递归,消除小括号
                subExpression = GetExpression(subExpression);
            }
            else
            {
                //不存在右小括号,但存在左小括号,则表达式非法
                leftParenthesisIndex = expression.IndexOf('(');
                if (leftParenthesisIndex >= 0)
                {
                    throw new Exception($"表达式【{expression}】非法,缺少结束右小括号")"");
                }
                //这里解析 没有小括号之间的内容,比如:4-9/4.0
                subExpression = ArithmeticWithoutParenthesis(expression);
                EventDisplayProcess?.Invoke($"这里进行四则运算,源表达式【{expression}】,简化后结果【{subExpression}】");
            }
            return subExpression;
        }

        /// <summary>
        /// 【没有小括号的】四则运算,先乘除(Multiply,Divide),再加减(Add,Subtract)
        /// </summary>
        /// <param name="expression"></param>
        public static string ArithmeticWithoutParenthesis(string expression)
        {
            string resultMultiplyDivide = CalculateMultiplyDivide(expression);
            return resultMultiplyDivide;//乘除的结果
        }

        /// <summary>
        /// 四则运算,先计算乘除法,如果没有乘除法,就计算加减法
        /// </summary>
        /// <param name="expression"></param>
        private static string CalculateMultiplyDivide(string expression)
        {
            int indexMultiply = expression.IndexOf('*');
            int indexDivide = expression.IndexOf('/');
            string simplifiedExpression = string.Empty;
            double finalResult;
            if (indexMultiply >= 0 && indexDivide >= 0)
            {
                //既有乘以,又有除以,则找出第一个乘或除
                int minIndex = Math.Min(indexMultiply, indexDivide);
                simplifiedExpression = GetSimplifiedExpressionForMultiplyDivide(expression, minIndex, minIndex == indexMultiply ? OperatorSymbol.Multiply : OperatorSymbol.Divide);
            }
            else if (indexMultiply >= 0)
            {
                //只有乘以,没有除以
                simplifiedExpression = GetSimplifiedExpressionForMultiplyDivide(expression, indexMultiply, OperatorSymbol.Multiply);
            }
            else if (indexDivide >= 0)
            {
                //只有除以,没有乘以
                simplifiedExpression = GetSimplifiedExpressionForMultiplyDivide(expression, indexDivide, OperatorSymbol.Divide);
            }
            else
            {
                //没有乘以,也没有除以,此时只用考虑加减操作,如 3+5-2
                simplifiedExpression = CalculateAdditionSubtract(expression);
            }
            if (double.TryParse(simplifiedExpression, out finalResult))
            {
                EventDisplayProcess?.Invoke($"已计算出【乘除】最终结果【{simplifiedExpression}】,源表达式【{expression}】");
                return simplifiedExpression;
            }
            if (indexMultiply >= 0 || indexDivide >= 0)
            {
                //这里,继续递归,计算出乘除的结果,依次消除所有的乘除号
                simplifiedExpression = CalculateMultiplyDivide(simplifiedExpression);
            }
            return simplifiedExpression;
        }

        /// <summary>
        /// 计算只有加法、减法的表达式
        /// </summary>
        /// <param name="expression"></param>
        private static string CalculateAdditionSubtract(string expression)
        {
            double finalResult;
            string simplifiedExpression = string.Empty;
            if (double.TryParse(expression, out finalResult))
            {
                return expression;
            }
            //没有乘以,也没有除以,此时只用考虑加减操作,如 3+5-2
            int indexAdd = expression.IndexOf('+');
            int indexSubtract = expression.IndexOf('-');
            if (indexAdd >= 0 && indexSubtract >= 0)
            {
                //同时存在 加号、减号
                int minIndex = Math.Min(indexAdd, indexSubtract);
                simplifiedExpression = GetSimplifiedExpressionForAddSubtract(expression, minIndex, minIndex == indexAdd ? OperatorSymbol.Addition : OperatorSymbol.Subtract);                
            }
            else if (indexAdd >= 0)
            {
                //存在加号,不存在减号
                simplifiedExpression = GetSimplifiedExpressionForAddSubtract(expression, indexAdd, OperatorSymbol.Addition);
            }
            else if (indexSubtract >= 0)
            {
                //不存在加号、存在减号
                simplifiedExpression = GetSimplifiedExpressionForAddSubtract(expression, indexSubtract, OperatorSymbol.Subtract);
            }
            else
            {
                //不存在加号、也不存在减号
                if (double.TryParse(expression, out finalResult))
                {
                    return expression;
                }
            }
            if (indexAdd >= 0 || indexSubtract >= 0)
            {
                //如果存在加号 或者 减号,继续递归,直到 消除所有的加减号
                simplifiedExpression = CalculateAdditionSubtract(simplifiedExpression);
            }
            return simplifiedExpression;
        }

        /// <summary>
        /// 获取【加减后】简化的表达式
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="minIndex"></param>
        /// <param name="operatorSymbol"></param>
        /// <returns></returns>
        private static string GetSimplifiedExpressionForAddSubtract(string expression, int minIndex, OperatorSymbol operatorSymbol)
        {
            StringBuilder sb = new StringBuilder();
            double left;
            string leftString = expression.Substring(0, minIndex);
            if (!double.TryParse(leftString, out left))
            {
                throw new Exception($"无法将字符串【{leftString}】转化为浮点数,请检查表达式");
            }
            double right;
            string rightString = string.Empty;
            int firstRightSymbol = expression.IndexOfAny(new char[] { '+', '-' }, minIndex + 1);
            if (firstRightSymbol == -1)
            {
                rightString = expression.Substring(minIndex + 1);
            }
            else
            {
                rightString = expression.Substring(minIndex + 1, firstRightSymbol - minIndex - 1);
            }
            if (!double.TryParse(rightString, out right))
            {
                throw new Exception($"无法将字符串【{rightString}】转化为浮点数,请检查表达式");
            }
            double result = 0;
            switch (operatorSymbol)
            {
                case OperatorSymbol.Addition:
                    result = left + right;
                    break;
                case OperatorSymbol.Subtract:
                    result = left - right;
                    break;
            }
            sb.Append(result);
            if (firstRightSymbol >= 0)
            {
                sb.Append(expression.Substring(firstRightSymbol));
            }
            string simplifiedExpression = sb.ToString();
            EventDisplayProcess?.Invoke($"【加减后】简化后的表达式为【{simplifiedExpression}】,源表达式【{expression}】");
            return simplifiedExpression;
        }

        /// <summary>
        /// 获取【乘除后】简化的表达式
        /// </summary>
        /// <param name="expression">源表达式</param>
        /// <param name="minIndex">乘除号所在的最小索引</param>
        /// <param name="operatorSymbol">操作符</param>
        /// <returns></returns>
        private static string GetSimplifiedExpressionForMultiplyDivide(string expression, int minIndex, OperatorSymbol operatorSymbol)
        {
            StringBuilder sb = new StringBuilder();
            //将1+8-2*3 转化为1+8-6 【即 2*3直接计算为6】
            int lastLeftSymbol = -1;//找出【乘号左边的】最后一个 加减号
            int firstRightSymbol = -1;//找出【乘号右边的】第一个 加减乘除号
            //LastIndexOfAny:从当前索引处,向前(左)查找多少个
            //倒序查找加号 或 减号,没有就是全部【乘号的前面 已经 没有 乘除了】
            lastLeftSymbol = expression.LastIndexOfAny(new char[] { '+', '-' }, minIndex, minIndex);
            //IndexOfAny:正序查找任何一个符号,从当前索引处,向后(右)查找多少个
            firstRightSymbol = expression.IndexOfAny(new char[] { '+', '-', '*', '/' }, minIndex + 1);
            double left;
            string leftString = string.Empty;
            if (lastLeftSymbol == -1)
            {
                leftString = expression.Substring(0, minIndex);
            }
            else
            {
                leftString = expression.Substring(lastLeftSymbol + 1, minIndex - lastLeftSymbol - 1);
            }
            if (!double.TryParse(leftString, out left))
            {
                throw new Exception($"无法将字符串【{leftString}】转化为浮点数,请检查表达式");
            }
            double right;
            string rightString = string.Empty;
            if (firstRightSymbol == -1)
            {
                rightString = expression.Substring(minIndex + 1);
            }
            else
            {
                rightString = expression.Substring(minIndex + 1, firstRightSymbol - minIndex - 1);
            }
            if (!double.TryParse(rightString, out right))
            {
                throw new Exception($"无法将字符串【{rightString}】转化为浮点数,请检查表达式");
            }
            double result = 0;
            switch (operatorSymbol)
            {
                case OperatorSymbol.Multiply:
                    result = left * right;
                    break;
                case OperatorSymbol.Divide:
                    result = left / right;
                    break;
            }
            if (lastLeftSymbol == -1)
            {
                sb.Append(result);
            }
            else
            {
                sb.Append(expression.Substring(0, lastLeftSymbol + 1));
                sb.Append(result);
            }
            if (firstRightSymbol >= 0)
            {
                sb.Append(expression.Substring(firstRightSymbol));
            }
            string simplifiedExpression = sb.ToString();
            EventDisplayProcess?.Invoke($"【乘除后】简化后的表达式为【{simplifiedExpression}】,源表达式【{expression}】");
            return simplifiedExpression;
        }
    }    
}

窗体FormCalculate的主要代码如下(忽略设计器自动生成的代码):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CalculateUseStackAndRecursionDemo
{
    public partial class FormCalculate : Form
    {
        public FormCalculate()
        {
            InitializeComponent();

            RecursionCalculateUtil.EventDisplayProcess += RecursionCalculateUtil_EventDisplayProcess;
        }

        private void RecursionCalculateUtil_EventDisplayProcess(string message)
        {
            this.BeginInvoke(new Action(() => 
            {
                if (rtxbDisplay.TextLength > 40960)
                {
                    rtxbDisplay.Clear();
                }
                rtxbDisplay.AppendText($"{DateTime.Now.ToString("HH:mm:ss.fff")}--->{message}
");
                rtxbDisplay.ScrollToCaret();
            }));
        }

        private void btnRecursion_Click(object sender, EventArgs e)
        {
            txbResult.Clear();
            rtxbDisplay.Clear();
            try
            {
                string result = RecursionCalculateUtil.GetExpression(rtxbExpression.Text);
                txbResult.Text = result;
            }
            catch (Exception ex)
            {
                RecursionCalculateUtil_EventDisplayProcess($"出错:{ex.Message}");
                MessageBox.Show(ex.Message, "出错");
            }
        }

        private void btnStack_Click(object sender, EventArgs e)
        {

        }
    }
}

程序测试如图:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值