IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> C#使用递归和堆栈计算含有小括号,加减乘除的表达式(2) -> 正文阅读

[开发工具]C#使用递归和堆栈计算含有小括号,加减乘除的表达式(2)

接上一篇,上一篇我们使用递归消元的方式进行表达式计算

C#使用递归和堆栈计算含有小括号,加减乘除的表达式(1)_斯内科的博客-CSDN博客

这次我们使用栈Stack<T>的方式:

思路:

1.生成数字和运算符列表:根据运算符的优先级,依次添加到堆栈中,生成的列表不存在左右小括号,只有数字 以及 加减乘除运算符。

2.解析列表:计算数字与运算符列表,如果遇到数字时,就进入栈中。如果遇到任何一个运算符时,就使用该运算符计算前两个数字【连续出栈两个数字】,然后将结果放入栈中,直到栈没有任何运算符就终止。此时栈只有一个数字,就是最终结果

整体代码:

新建类文件StackCalculateUtil.cs,

关键类StackCalculateUtil源代码如下:

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

namespace CalculateUseStackAndRecursionDemo
{
    class StackCalculateUtil
    {
        /// <summary>
        /// 显示计算过程事件
        /// </summary>
        public static event Action<string> EventDisplayProcess;
        /// <summary>
        /// 根据运算符的优先级,依次添加到堆栈中
        /// 最终返回的列表不存在左右小括号,只有数字 以及 加减乘除运算符
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static List<string> ArithmeticToList(string expression)
        {
            string outstr = string.Empty;
            //表达式 1+2+7*(12.3-(12+9)/3)-(1.1+6.6)+4*5.2
            Stack<string> stack = new Stack<string>();
            List<string> list = new List<string>();
            int i = 0;
            while (i < expression.Length)
            {
                if (expression[i] == '+' || expression[i] == '-')
                {
                    //遇到加减时,如果顶部元素不为 左小括号,就一直出栈,并放入到列表中
                    while (stack.Count > 0 && stack.Peek() != "(")
                    {
                        outstr = stack.Pop();
                        list.Add(outstr);
                    }
                    stack.Push(expression[i].ToString());
                    i++;
                }
                else if (expression[i] == '*' || expression[i] == '/')
                {
                    //遇到乘除时,如果顶部元素是 乘或除,就一直出栈,并放入到列表中
                    while (stack.Count > 0 && (stack.Peek() == "*" || stack.Peek() == "/"))
                    {
                        outstr = stack.Pop();
                        list.Add(outstr);
                    }
                    stack.Push(expression[i].ToString());
                    i++;
                }
                else if (expression[i] == '(')
                {
                    //遇到左括号时,直接入栈
                    stack.Push(expression[i].ToString());
                    i++;
                }
                else if (expression[i] == ')')
                {
                    //遇到右括号时,直接出栈
                    if (stack.Count == 0)
                    {
                        throw new Exception($"括号不是成对出现的,表达式【{expression}】非法");
                    }
                    outstr = stack.Pop();
                    //遇到右括号,就一直出栈,直到遇到左括号 就终止
                    while (stack.Count > 0 && (string.IsNullOrEmpty(outstr) || outstr != "("))
                    {
                        list.Add(outstr);
                        outstr = stack.Pop();
                    }
                    i++;
                }
                else
                {
                    //数字和小数点 一直累加,直到(字符串结束 或者 遇到运算符)
                    outstr = string.Empty;
                    while (i < expression.Length && expression[i] != '+' && expression[i] != '-'
                        && expression[i] != '*' && expression[i] != '/' && expression[i] != '(' && expression[i] != ')')
                    {
                        outstr += expression[i];
                        i++;
                    }
                    list.Add(outstr);
                }
            }
            //将剩余的字符出栈
            while (stack.Count > 0)
            {
                list.Add(stack.Pop());
            }
            return list;
        }

        /// <summary>
        /// 计算数字与运算符列表,如果遇到数字时,就进入栈中。如果遇到任何一个运算符时,就使用该运算符计算前两个数字【连续出栈两个数字】,
        /// 然后将结果放入栈中,直到栈没有任何运算符就终止。此时栈只有一个最终结果
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static string CalculateSequenceList(List<string> list)
        {
            Stack<string> stack = new Stack<string>();
            for (int i = 0; i < list.Count; i++)
            {
                double x;
                double y;
                double simpleResult;
                if (list[i] == "+")
                {
                    simpleResult = ValidateData(stack, OperatorSymbol.Addition, out x, out y);
                    //将计算结果放入栈中
                    stack.Push(simpleResult.ToString());
                    EventDisplayProcess?.Invoke($"已计算出【{x}+{y}={simpleResult}】,并将结果入栈");
                }
                else if (list[i] == "-")
                {
                    simpleResult = ValidateData(stack, OperatorSymbol.Subtract, out x, out y);
                    stack.Push(simpleResult.ToString());
                    EventDisplayProcess?.Invoke($"已计算出【{x}-{y}={simpleResult}】,并将结果入栈");
                }
                else if (list[i] == "*")
                {
                    simpleResult = ValidateData(stack, OperatorSymbol.Multiply, out x, out y);
                    stack.Push(simpleResult.ToString());
                    EventDisplayProcess?.Invoke($"已计算出【{x}*{y}={simpleResult}】,并将结果入栈");
                }
                else if (list[i] == "/")
                {
                    simpleResult = ValidateData(stack, OperatorSymbol.Divide, out x, out y);
                    stack.Push(simpleResult.ToString());
                    EventDisplayProcess?.Invoke($"已计算出【{x}/{y}={simpleResult}】,并将结果入栈");
                }
                else
                {
                    stack.Push(list[i]);
                }
            }
            if (stack.Count > 0)
            {
                return stack.Pop();
            }
            return string.Empty;
        }

        /// <summary>
        /// 验证序列是否含有两个元素,以及这两个元素是否可以转化为浮点数
        /// </summary>
        /// <param name="stack"></param>
        /// <param name="operatorSymbol"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private static double ValidateData(Stack<string> stack, OperatorSymbol operatorSymbol, out double x, out double y)
        {
            if (stack.Count < 2)
            {
                throw new Exception($"非法的栈,集合个数少于2.栈集合为【{string.Join(",", stack)}】");
            }
            string yStr = stack.Pop();
            if (!double.TryParse(yStr, out y))
            {
                throw new Exception($"表达式【{yStr}】无法转化为浮点数");
            }
            string xStr = stack.Pop();
            if (!double.TryParse(xStr, out x))
            {
                throw new Exception($"表达式【{xStr}】无法转化为浮点数");
            }
            switch (operatorSymbol)
            {
                case OperatorSymbol.Multiply:
                    return x * y;
                case OperatorSymbol.Divide:
                    return x / y;
                case OperatorSymbol.Addition:
                    return x + y;
                case OperatorSymbol.Subtract:
                    return x - y;
            }
            return 0;
        }
    }
}

窗体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;
            StackCalculateUtil.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}\n");
                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)
        {
            txbResult.Clear();
            rtxbDisplay.Clear();
            try
            {
                List<string> list = StackCalculateUtil.ArithmeticToList(rtxbExpression.Text);
                RecursionCalculateUtil_EventDisplayProcess("获取到计算数字与运算符列表:\n" + string.Join("\n", list));
                RecursionCalculateUtil_EventDisplayProcess("【无小括号】开始数字和运算符计算:");
                string result = StackCalculateUtil.CalculateSequenceList(list);
                txbResult.Text = result;
            }
            catch (Exception ex)
            {
                RecursionCalculateUtil_EventDisplayProcess($"出错:{ex.Message}");
                MessageBox.Show(ex.Message, "出错");
            }
        }
    }
}

程序运行如图:

?

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:47:16  更:2022-03-24 00:47:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:26:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码