c#栈应用之实现四则运算

前言:四则运算,大家都不陌生,在上小学的时候,数学中学到过的知识,那么如何在程序中实现呢?下面,我们就用程序来实现9+(3-2)*(5-3)/4*3,这个算式的值。计算的时候,有一个规则”先乘除,后加减,从左到右,先括号内后括号外“。

其优先级就是 加减<乘除<括号

这个算式,我们可以很轻松的计算出它的值等于10.5。这是我们常用的四则表达式,又叫做中缀表达式。这种计算的复杂之处在与乘除在加减之后,并且还有括号,放在程序里的判断,就复杂了,那么如何简化呢?伟大的科学家想到了好的处理办法,

一、逆波兰(Reverse Polish Notation,RPN):一种不需要括号的后缀表达法,我们也称之为逆波兰。

上面的四则运算表达式,转换未后缀表达法之后,变为 9 3 2 - * 5 3 - 4 / 3 * +,叫后缀的原因所有的符号都是在要运算数字的后面出现。

如何实现由中缀表达式转化未后缀表达式呢?

规则:依次从左向右遍历表达式,若是数字加入到集合;若是符号,则需要判断其与栈顶符号的优先级,如果当前元素是右括号或优先级较低的符号,则栈顶的元素一次出栈并输出,并将当前符号进栈;如果当前元素和栈顶的元素优先级相同,将栈顶的同级元素依次出栈。

实现代码:

/// <summary>
/// 利用正则表达式,分别获取数字和符号,然后组装到集合中。
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private List<string> GetOpList(string str)
{string pattern = (@"\d+");Regex validate = new Regex(pattern);MatchCollection col = validate.Matches(str);//string patternFh = (@"(\+|\-|\*|\/|\(|\))");string patternFh = @"\D+";Regex validateFh = new Regex(patternFh);MatchCollection colFh = validateFh.Matches(str);List<string> list = new List<string>();int nFhIndex = 0;for (int i = 0; i < col.Count; i++){Match mD = col[i];list.Add(mD.Value);if (nFhIndex < colFh.Count){Match mf = colFh[nFhIndex];string strTemp = mf.Value;int nTempLen = strTemp.Length;for(int j = 0; j < nTempLen; j++){list.Add(strTemp.Substring(j, 1));}nFhIndex++;}}return list;
}/// <summary>
/// 当前只限定加减乘除小括号
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private List<string> GetNextPrevRegex(string str)
{string hig = "*/";   //优先级高的string zkh = "(";    //左括号string ykh = ")";    //右括号Stack stack = new Stack();List<string> list = new List<string>();List<string> listOp = GetOpList(str);//从左到右遍历中缀表达式的每个数字和符号,for (int i = 0; i < listOp.Count; i++){string item = listOp[i];//1、若是数字输出,即成为后缀表达式的一部分;if (IsNumeric(item)){list.Add(item);continue;}if (stack.Count == 0 || zkh == item){stack.Push(item);continue;}//这里限定了默认条件,是必须+-*/),才到这里。while (stack.Count > 0){string ab = stack.Peek().ToString();if (ykh == item){if (zkh == ab){stack.Pop();  //将左括号出栈break;}list.Add(stack.Pop().ToString());continue;}if (!hig.Contains(ab))break;list.Add(stack.Pop().ToString());}if (!ykh.Contains(item))stack.Push(item);}while (stack.Count > 0){list.Add(stack.Pop().ToString());}return list;
}private bool IsNumeric(string token)
{bool blag = true;string pattern = (@"^\d+$");Regex validate = new Regex(pattern);if (!validate.IsMatch(token)){blag = false;}return blag;
}

二、由上面计算得到后缀表达式,那么如何使用栈来计算这个表达式呢?

计算规则:依次遍历后缀表达式,如果是数字,则入栈,如果是符号,则将栈顶的两个元素出栈,进行计算,计算完成之后,将结果入栈。

代码如下:

public double GetResult(string calc)
{List<string> list = GetNextPrevRegex(calc);Stack calcStack = new Stack();foreach (var item in list){string temp = item.ToString();//如果是数字,入栈if (IsNumeric(temp)){calcStack.Push(temp);continue;}//如果是符号,则把栈顶的两个数字出栈,进行计算,入栈。double.TryParse(calcStack.Pop().ToString(), out double hz2);double.TryParse(calcStack.Pop().ToString(), out double hz1);double result = GetResultByFh(hz1, hz2, temp);calcStack.Push(result);}string sResult = calcStack.Pop().ToString();double.TryParse(sResult, out double calcresult);return calcresult;
}
private double GetResultByFh(double ca1, double ca2, string fh)
{if (fh == "+")return ca1 + ca2;else if (fh == "-")return ca1 - ca2;else if (fh == "*")return ca1 * ca2;elsereturn ca1 / ca2;
}

备注:其中逆波兰解释,来自《大话数据结构》一书。

欢迎大家批评指正,小可不胜感激。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/13406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

流数据湖平台Apache Paimon(一)概述

文章目录 第1章 概述1.1 简介1.2 核心特性1.3 基本概念1.3.1 Snapshot1.3.2 Partition1.3.3 Bucket1.3.4 Consistency Guarantees一致性保证 1.4 文件布局1.4.1 Snapshot Files1.4.2 Manifest Files1.4.3 Data Files1.4.4 LSM Trees 第1章 概述 1.1 简介 Flink 社区希望能够将…

RocketMQ重复消费的解决方案::分布式锁直击面试!

文章目录 场景分析方法的幂等分布式锁Redis实现分布式锁抢锁的设计思路 分布式锁案例 直击面试rocketmq什么时候重复消费消息丢失的问题消息在哪里丢失发送端确保发送成功并且配合失败的业务处理消费端确保消息不丢失rocketmq 主从同步刷盘 场景分析 分布式系统架构中,队列是分…

css实现有缺口的border

css实现有缺口的border 1.问题回溯2.css实现有缺口的border 1.问题回溯 通常会有那种两个div都有border重叠在一起就会有种加粗的效果。 div1,div2,div3都有个1px的border&#xff0c;箭头标记的地方是没有处理解决的&#xff0c;很明显看着是有加粗效果的。其实这种感觉把di…

【Java从入门到大牛】集合进阶上篇

&#x1f525; 本文由 程序喵正在路上 原创&#xff0c;CSDN首发&#xff01; &#x1f496; 系列专栏&#xff1a;Java从入门到大牛 &#x1f320; 首发时间&#xff1a;2023年7月29日 &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43…

IntelliJ IDEA流行的构建工具——Gradle

IntelliJ IDEA&#xff0c;是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超常的。 如…

基于java SpringBoot和HTML的博客系统

随着网络技术渗透到社会生活的各个方面&#xff0c;传统的交流方式也面临着变化。互联网是一个非常重要的方向。基于Web技术的网络考试系统可以在全球范围内使用互联网&#xff0c;可以在本地或异地进行通信&#xff0c;大大提高了通信和交换的灵活性。在当今高速发展的互联网时…

如何使用Python进行数据挖掘?

使用Python进行数据挖掘需要掌握以下几个关键步骤&#xff1a; 数据收集&#xff1a;首先&#xff0c;你需要获取你要进行数据挖掘的数据。可以从公共数据集、API、数据库等各种来源收集数据。 数据清洗&#xff1a;清洗数据是一个重要的步骤&#xff0c;它包括去除重复数据、…

【达哥讲网络】第3集:数据交换的垫基石——二层交换原理

专业的网络工程师在进行网络设计时&#xff0c;会事先规划好不同业务数据的转发路径&#xff0c;一方面是为了满足用户应用需求&#xff0c;另一方面是为了提高数据转发效率、充分利用各设备/各链路的硬件或带宽资源。在进行网络故障排除时&#xff0c;理顺各路数据的转发路径也…

K8s:K8s 20个常用命令汇总

写在前面 博文内容为节译整理&#xff0c;用于温习理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都是不完整的&#xff0c;是人的逃避方式&#xff0…

【Oracle】session_cached_cursors和open_cursors的调整

在进行数据迁移&#xff0c;数据导入慢&#xff0c;经查询可能为session_cached_cursors和open_cursors配置异常导致&#xff0c;遂调整参数值 查看参数 -查看session_cached_cursors SQL> show parameter session_cached_cursors;查看使用情况 SELECT session_cached_c…

【Luogu】 P5176 公约数

题目链接 点击打开链接 题目解法 首先证明一个结论&#xff1a; ( i j , i k , j k ) ( i , j ) ( i , k ) ( j , k ) ( i , j , k ) (ij,ik,jk)\frac{(i,j)(i,k)(j,k)}{(i,j,k)} (ij,ik,jk)(i,j,k)(i,j)(i,k)(j,k)​ 考虑对于 i , j , k i,j,k i,j,k 的质因子 p p p 的次…

Android在子线程中对UI进行操作——AsyncTask

以下内容摘自郭霖《第一行代码》第三版 使用AsyncTask AsyncTask是一个抽象类&#xff0c;所以如果我们想使用它&#xff0c;就必须创建一个子类去继承它。在继承时我们可以为AsyncTask类指定3个泛型参数&#xff1a; Params。在执行AsyncTask时需要传入的参数&#xff0c;可…

精细呵护:如何维护自己的电脑,提升性能和寿命

导语&#xff1a; 在当今数字化时代&#xff0c;电脑已经成为我们日常生活和工作的必需品。然而&#xff0c;就像任何其他设备一样&#xff0c;电脑需要得到适当的维护和保养&#xff0c;以保持良好的性能和延长使用寿命。在本文中&#xff0c;我们将分享一些简单而有效的方法&…

AI For Engineers 线上参会指南

AI For Engineers 线上参会指南 欢迎您报名参加 AI For Engineers&#xff1a;工程师 AI 全球会议&#xff0c;为了让各位参会者参会体验更佳&#xff0c;更好地利用本次会议收获更多。Altair 特别为各位准备了线上参会指南&#xff0c;一起来看看吧~ 会议时间&#xff1a;20…

掌握Python的X篇_12_如何使用VS Code调试Python程序

本篇将会介绍如何使用VS Code调试Python程序。 文章目录 1. 什么是调试2. 断点3. 如何启动调试4. 监视窗口5. 单步 1. 什么是调试 我们可以利用VS Code对Python代码进行调试。所谓调试&#xff0c;大家可以理解成有能力将程序进行 “慢动作播放”让我们有机会看到程序一步一步…

flutter minio

背景 前端 经常需要上传文件 图片 视频等等 到后端服务器&#xff0c; 如果到自己服务器 一般会有安全隐患。也不方便管理这些文件。如果要想使用一些骚操作 比如 按照前端请求生成不同分辨率的图片&#xff0c;那就有点不太方便了。 这里介绍以下 minio&#xff0c;&#xff0…

flutter开发实战-父子Widget组件调用方法

flutter开发实战-父子Widget组件调用方法 在最近开发中遇到了需要父组件调用子组件方法&#xff0c;子组件调用父组件的方法。这里记录一下方案。 一、使用GlobalKey 父组件使用globalKey.currentState调用子组件具体方法&#xff0c;子组件通过方法回调callback方法调用父组…

PHP-Mysql图书管理系统--【白嫖项目】

强撸项目系列总目录在000集 PHP要怎么学–【思维导图知识范围】 文章目录 本系列校训本项目使用技术 首页phpStudy 设置导数据库后台的管理界面数据库表结构项目目录如图&#xff1a;代码部分&#xff1a;主页的head 配套资源作业&#xff1a; 本系列校训 用免费公开视频&am…

java设计模式-工厂模式(上)

什么是工厂模式 工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。通过使用工厂模式&#xff…

LeetCode32.Longest-Valid-Parentheses<最长有效括号>

题目&#xff1a; 思路&#xff1a; 遍历括号.遇到右括号然后前一个是左括号 那就res2,然后重定位 i 的值 并且长度减少2; 但是问题在于无法判断最长的括号.只能得到string内的全部括号长度. 错误代码: 写过一题类似的,那题是找括号数.记得是使用的栈,但是死活写不出来. 看完…