首先介绍几个概念

中缀式:平常我们所用到的标准的四则运算表达式就是中缀式,如9+(3-1)*3+10/2,这就是一个中缀式

后缀式(逆波兰式):一种不需要括号的后缀表达法,我们也把他称为逆波兰式,如将上面的中缀式改为后缀式则是:9 3 1 - 3 * + 10 2 / +。

通过观察中缀式发现,括号都是成对出现的,有左括号就一定有右括号,对于多重括号,最终也是完全嵌套匹配的。这用栈的结构存储正好合适,只要碰到左括号,就将左括号入栈,不管表达式有多少重括号,反正遇到左括号就入栈,而后面出现的右括号时,就让栈顶的左括号出栈,期间让数字进行运算,这样,最终有括号的表达式从左到右巡查一遍,栈应该是由空到有元素,最终再因全部匹配成功后成为空栈。

注:以下都以表达式 9 + ( 3 - 1 ) * 3 + 10 / 2来讲解

如何将中缀式改为后缀式呢???

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

初始化一空栈,用来对符号入出栈使用,如下左图所示

第一个字符是数字9,输出9,后面是符号‘+’入栈,如下右图所示

3.第三个字符是‘( ’,依然是符号,因其只是左括号,还未配对,故入栈,如下左图所示

4.第四个字符是数字3,输出,总表达式为9 3,接着是‘-’,入栈,如下右图所示

5.接下来是数字1,输出,总表达式是9 3 1,后面是符号‘  )’,此时,我们需要去匹配此前的‘(  ’,所以栈顶一次出栈,并输出,直到‘(  ’出栈为止。此时左括号上方只有‘-’,因此输出‘-’。总的输出表达式为9 3 1 -,如下左图所示。

6.紧接着是符号‘*’,因为此时的栈顶符号是‘+’,优先级低于‘*’,因此不输出,‘*’入栈,接着是数字3,输出,总的表达式为9 3 1 - 3。如下右图所示。

7.之后是符号‘+’,此时当前元素栈顶元素‘*’比‘+’优先级高,因此栈中元素出栈并输出(没有比‘+’优先级更低的了,所以全部出栈),总输出为9 3 1 - 3 * +,然后将当前的这个符号‘+’入栈,也就是说,前6张图的栈底的‘+’是指中缀式开头的9后面的那个‘+’,而下左图栈底的‘+’是指9+(3-1)*3+中的最后一个‘+’。

8.紧接着是数字10,输出,总表达式为9 3 1 - 3 * + 10.后是符号‘/’,入栈,如下右图所示

9.最后一个数字2,输出,总表达式为9 3 1 - 3 * + 10 2,如下左图所示。

10.因已经到了最后,所以将栈中符号全部出栈并输出,最终输出的后缀表达式结果是9 3 1 - 3  * + 10 2 / +,如下右图所示。

Java代码:

package infixForm;

import java.util.*;

class input {

//public ArrayListrpnArr = new ArrayList<>(); //用于存储逆波兰式

int flag = 0; //用于记录存储的顺序

public MapintMap = new HashMap<>(); //用于存储数字

public MapcharMap = new HashMap<>(); //用于存储运算符

private Mapmap = new HashMap<>(); /*用于存四则运算符号的优先级*/

private ArrayListsum = new ArrayList<>(); /*可能不是一位数字,那么就需要对每个数字线存储起来,遇到符号时就将存储起来的数字进行运算*/

private Stackstack = new Stack<>(); /*存储四则运算的符号*/

private int add = 0;

/*对每个字符进行相应的处理*/

public void analyze(String arithmetic) {

/*定义四则运算符号的优先级*/

map.put('+', 1);

map.put('-', 1);

map.put('*', 2);

map.put('/', 2);

map.put('(', 3);

map.put(')', 3);

for (int i = 0; i < arithmetic.length(); i++) {

char nowChar = arithmetic.charAt(i); /*取出第一个字符*/

if (nowChar == '+' || nowChar == '-' || nowChar == '*' || nowChar == '/' || nowChar == '(' || nowChar == ')') { /*如果是运算符,就要准备入栈了*/

if (sum.size() != 0) { /*入栈之前要先将存储在sum里的数据输出出来*/

summation();

}

if (nowChar != ')' && (stack.empty() || map.get(nowChar) > map.get(stack.peek()) || stack.peek() == '(')) { /*入栈*/

stack.push(nowChar);

} else {

while (!stack.isEmpty() && nowChar >= map.get(stack.peek())) { /*当栈不为空并且当前运算符的优先级不小于栈顶运算符时*/

if (stack.peek() == '(' || stack.peek() == ')') { /*对于括号运行符不需要进行输出*/

stack.pop();

break;

}

charMap.put(flag++, stack.pop());

}

if (nowChar != ')') { /*将当前运算符入栈,如果是右括号的话就不用入栈了,因为当遇到右括号是,栈里面必然有左括号,所以右括号要随着左括号一起丢掉*/

stack.push(nowChar);

}

}

continue;

} else { /*当不是运算符时,就进行数字的处理*/

int num = Integer.valueOf(nowChar) - 48; /*Integer.valueOf(nowChar)输出的是字符的ASCII码值,要将它转化为实际数字*/

sum.add(num); /*可能不是一位数,所以可以先将该数字存储起来*/

}

}

if (sum.size() != 0) { /*此时sum里面可能还会有存储起来的数字,但还没输出,此时要进行输出了*/

for (int j = 0; j < sum.size(); j++) {

summation();

}

}

while (!stack.isEmpty()) { /*和上面的原因一样*/

charMap.put(flag++, stack.pop());

}

}

/*将数组中的数字求和*/

public void summation() {

int pow = 0;

for (int j = sum.size() - 1; j >= 0; j--) {

add = (int) (add + sum.get(j) * Math.pow(10, pow++)); /*求幂运算*/

}

sum.clear(); /*清除ArrayList集合*/

intMap.put(flag++, add);

add = 0; /*归零,不然下次会接着累加*/

}

}

得到了后缀式,那么如何由后缀式计算出结果呢?

规则:从左到右遍历表达式的每个数字和字符,遇到是数字就入栈,遇到树符号,就将处于栈顶的两个数字出栈,进行运算,运算结果入栈,一直到最终获得结果。

1.初始化一个空栈,此栈用来对要运算的数字进出使用,如下左图所示。

2.后缀式中的前三个都是数字,所以9 3 1入栈,如下右图所示。

3.接下来是‘-’,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再将2入栈,如下左图所示

4.接着是数字3入栈,如下右图所示

5.后面是‘*’,也就意味着栈中的3和2出栈,2和3相乘,得到6,并将6入栈,如下左图所示

6.下面是‘+’,所以栈中的6和9出栈,9和6相加,得到15,将15入栈,如下右图所示

7.接着是10和2两数字入栈,如下左图所示

8.接下来是符号‘/’,因此,栈顶的2和10出栈,10和2相除,得到5,将5入栈,如下右图所示

9.最后一个是符号‘+’,所以15和5出栈并相加,得到20,将20入栈,如下左图所示

10.结果是20入栈,栈变为空,如下右图所示

Java代码:

package infixForm;

import java.util.Map;

import java.util.Scanner;

import java.util.Stack;

public class output {

private static input in = new input();

public static void main(String[] args) {

//String arithmetic = "6+(8-7)+5*6+9-12/2"; /*输入的表达式*/

Scanner scanner = new Scanner(System.in);

String arithmetic = scanner.next();

in.analyze(arithmetic);

operation(in.intMap, in.charMap);

}

public static void operation(MapintMap, MapcharacterMap) {

Stackstack = new Stack<>(); /*用于存放数据*/

for (int i = 0; i < in.intMap.size() + in.charMap.size(); i++) { /*遍历两个集合*/

if (in.intMap.get(i) == null) {

switch (in.charMap.get(i)) {

case '-': /*因为是减号,所以要考虑顺序*/

int one = stack.pop();

int two = stack.pop();

stack.push(two - one);

break;

case '+':

stack.push(stack.pop() + stack.pop());

break;

case '*':

stack.push(stack.pop() * stack.pop());

break;

case '/': /*同减号,是因为顺序*/

int first = stack.pop();

int second = stack.pop();

stack.push(second / first);

break;

}

} else {

stack.push(in.intMap.get(i));

}

}

System.out.print("结果是:" + stack.pop());

}

}

运行结果:

总结:

从以上推导中可以看出,想要计算机具有处理我们通常的标准(中缀)表达式的能力,最重要的就是两步:

将中缀式转化为后缀式(栈用来进出运算符)。

将后缀式进行运算得到结果(栈用来进出运算的数字)。

栈运算 java_栈的应用——四则运算表达式求值(Java实现)相关推荐

  1. c语言求不定式的最大值,C语言之四则运算表达式求值(链栈)—支持浮点型数据,负数, 整型数据运算...

    运算符间的优先级关系: 链栈结构体定义: 数据域使用字符串长度为20的字符数组(故需要注意判断读取的字符串是运算符还是数值) 可支持浮点型数据,负数, 整型数据的运算 float EvaluateEx ...

  2. 栈的应用(递归:例子裴波那契数列 四则运算表达式求值 :后缀(逆波兰) )

    递归: -栈有一个很重要的应用:在程序设计语言中实现递归. 当你往镜子前面一站,镜子里面就有-一个你的像. 但你试过两面镜子一起照吗?如果A.B两面镜子相互面对面放着,你往中间- -站,嘿,两面镜子里 ...

  3. 四则运算表达式求值の各种心碎

    实验三---四则运算表达式求值 一.基本要求: ( 1 ) 利用二叉树后序遍历来实现表达式的转换,同时可以使用实验三的结果来求解后缀表达式的值. ( 2) 输入输出格式: 输入格式:在字符界面上输入一 ...

  4. Bailian4132 四则运算表达式求值【文本处理】

    4132:四则运算表达式求值 总时间限制: 1000ms 内存限制: 65536kB 描述 求一个可以带括号的小学算术四则运算表达式的值 输入 一行,一个四则运算表达式.''表示乘法,'/'表示除法 ...

  5. 分别用C++和JavaScript 实现四则运算表达式求值

    博主16年4.19去面腾讯实习生,其中一个问题是让写一个函数求四则运算表达式的值,输入是字符串,输出为表达式结果.当时只记得这是数据结构里堆栈的应用,表达式要变顺序,但是实现就想不起来了,自然程序写的 ...

  6. 栈与队列及其应用 - 1.算术表达式求值

    使用到了ArrayDeque集合:使用ArrayDeque表示Queue比LinkedList.表示Stack效率更高 ArrayDeque使用详解 package com.kiger.Demo;im ...

  7. 中缀表达式求值 Java

    什么是中缀表达式: 中缀表达式的计算逻辑: 例:(10+20/2*3)/2+8 我们要按照四则运算的逻辑进行计算: (1)先计算括号内的计算单元,而内部的计算单元必须要按照四则运算的优先级来进行即先乘 ...

  8. 四则运算表达式求值(栈的应用)

    1.前/中/后缀表达式的转换(首先需要明白三者之间的转换)    自然表达式转换为前/中/后缀表达式,其实是很简单的.首先将自然表达式按照优先级顺序,构造出与表达式相对应的二叉树,然后对二叉树进行前/ ...

  9. 【Leetcode栈与队列】150. 逆波兰表达式求值(后缀表达式求值,看作对对碰游戏)

    文章目录 Leetcode150 1.问题描述 2.解决方案 3.计算机的思考方式 Leetcode150 1.问题描述 2.解决方案 1.逆波兰表达式优点 2.逆波兰表达式相当于是二叉树中的后序遍历 ...

最新文章

  1. android radiobutton 分组,Android 第十课——UI RadioButton
  2. android开发之svg全面总结
  3. 聚焦 AI + 大数据全球视野引领行业创新升级
  4. 阿里云正式推出高防DDoS专家服务
  5. SFTP是什么?与FTP之间有什么区别
  6. 合泰单片机c语言halt指令,holtek单片机图文全面详解
  7. 《高效能人士的7个习惯》读后摘记
  8. 变频器按启动没反应_ABB变频器启动无反应维修那些事
  9. MYSQL数据库SQL语句练习实验 EXERCISES. 1 SIMPLE COMMANDS
  10. C语言之联合与变体记录
  11. PHP保存图片并且修改图片分辨率(DPI)
  12. 360怎么修改域名服务器地址,怎样修改DNS地址
  13. typecho添加html5视频播放器,DPlayer-Typecho视频播放插件
  14. python按钮点击事件wx_wx.python事件的绑定
  15. Selenium面试问题及答案30题版
  16. 超声波清洗机是什么?
  17. 华为实验跨交换机不同vlan通信
  18. android adb 模拟长按,adb 模拟长按电源键
  19. Discrete regularity for graph Laplacians --Jeff Calder 读书笔记 part1 待更
  20. java-php-python-springboot志愿者服务平台计算机毕业设计

热门文章

  1. 解决ubuntu下不能识别U盘的问题
  2. YOLO v1深入理解
  3. update inner join 使用
  4. 锁定计算机的快捷换,锁电脑快捷键【应对步骤】
  5. 不只测心率,通过AI可以测大学生压力水平
  6. 7年华为老员工被辞退,公司赔偿N+4,网友:多拿11个月工资,爽翻
  7. 引用类型和原始类型区别
  8. python 基础代谢率计算_【Python 20】BMR计算器4.0(异常处理)
  9. plink中的BGEN格式的数据如何用
  10. PDBbind Database (version 2020)