用栈实现基本计算器

本文介绍了如何使用栈实现一个基本的计算器,解析输入的字符串表达式,例如 '1 + 1' 和 '2 - 1 + 2'。讨论了逆波兰表达式的优势,以及如何将其应用于复杂表达式的求值。文中提到了从中缀表达式转换为逆波兰表达式的调度车算法,并提供了栈和数组模拟栈两种解法的思路。
摘要由CSDN通过智能技术生成

基本计算器


1.1 问题描述

实现一个基本的计算器来计算一个简单的字符串表达式 s 的值。

示例 1:

​ 输入:s = “1 + 1”
​ 输出:2

示例 2:

​ 输入:s = " 2-1 + 2 "
​ 输出:3

1.2 思路及复杂度分析

因为睡眠不好的原因,总觉得头胀胀的,精神状态不好,但每日算法的断更又是我所不能接受的。所以这一篇我就用了力扣官方的题解,来为大家解析一下思路并做适当延伸。

题目要求满足+/-两种操作符的运算,且操作数都为非负整数,而且包含括号

首先明确的是,对于这种表达式求值的问题,编译器对于表达式求值都是通过栈来实现的,我们这里也不例外。

另外小学的知识告诉我们有括号的话,应该先算括号里面的表达式,再将子表达式求解的结果作为表达式的一部分继续运算。此外,还有一个容易忽略的地方,那就是空格!!!很多人出于美观的编程习惯,会在表达式中加入空格,这样对表达式的求解并没有影响,但我们在编程时需要刻意的忽略空格。最后,需要注意的还有对操作数的处理,在一个字符串中123被认定为三个字符!我们需要使用十进制的运算知识将三个字符组合在一起处理。

到此,基本计算器的核心部分就完结了,具体的代码看最后的代码演示部分就ok了。

  • 注:在力扣题解区发现大牛的奇思妙想:https://leetcode-cn.com/problems/basic-calculator/solution/zhan-di-gui-20xing-dai-ma-chao-96-by-mantoufan/

您可能会说,我点进来你就给我看这个,不是说好有干货吗~

的确,在我看来呢,掌握上面的的确可以解决问题,但它不能作为一种解决问题的通用模式,依靠这种灵光一现的技巧是不长远的,对于表达式求值的问题,更通用的解法是逆波兰表达式——

刚好力扣上有这么一道题,我们来一起小试牛刀吧~

逆波兰表达式求值

根据 逆波兰表示法,求表达式的值。

有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

思路及复杂度分析


在分析之前,有必要先聊聊逆波兰表达式是什么,为什么它对于表达式的求解有帮助?

逆波兰表达式是一种利用栈来进行运算的数学表达式。我们通常使用的表达式是中缀表达式,比如:
( 1 + 2 ) ∗ ( 3 − 4 ) (1+2)*(3-4) (1+2)(34)
计算机求解时会将这个中缀表达式先解析为符号树,再求值。而解析符号树需要递归遍历这颗树,假如表达式比较复杂,也就是树的深度大时,会申请大量栈空间性能不高,而如果将中缀表达式变成后缀表达式时,情况就有所不同了,只需要很小的栈空间就可以完成操作。

说到这,你可能还是似懂非懂,同样的表达式内容,为什么逆波兰表达式效率就高呢~

这是因为逆波兰表达式可以简化表达式的内容,它设计的初衷就是因为可以省略括号,从而减少CPU运算的次数。


既然逆波兰表达式这么好用,那怎么将中缀表达式转化为逆波兰表达式呢?那就要看调度车算法咯——

规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于找顶符号(乘除优先加减)则栈顶元素依次出找并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

对于其具体的案例,可以移步这篇博文:http://www.nowamagic.net/librarys/veda/detail/2307


看到这的小伙伴可以舒一口气了,内功已成,剩下的招式就是信手拈来啦。但是追求更好的性能是一个coder应该有的习惯,所以我们会从数组模拟栈两种思路来求解——

栈求解

它的思路可谓非常朴素,我们先遍历数组,将所有的操作数入栈,当遇到运算符时,就取出栈顶的两个元素,并将运算的结果压栈,

将遍历得到的字符串转化为整数时,有一个小细节值得注意:是使用Integer.parseInt()还是Integer.ValueOf(),它们都可以将字符串转化为整数,但前者比起后者少了装箱的操作.

image-20210216234940724

数组模拟栈求解

虽然栈提供了对出栈入栈操作提供了方便的封装,但也导致其操作不灵活,就拿这句代码来看——

image-20210216235301216

完全可以用更简洁的数组代码实现:

image-20210216235403849

此外,只需要申请一个数组用于保存操作数即可,而假设一个表达式长度为n,则最怀情况下,这个表达式中只包含操作数,并且操作数只有一个,也就是
n / 2 + 1 n/2+1 n/2+

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值