栈运算 java_栈的应用——四则运算表达式求值(Java实现)
首先介绍几个概念
中缀式:平常我们所用到的标准的四则运算表达式就是中缀式,如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实现)相关推荐
- c语言求不定式的最大值,C语言之四则运算表达式求值(链栈)—支持浮点型数据,负数, 整型数据运算...
运算符间的优先级关系: 链栈结构体定义: 数据域使用字符串长度为20的字符数组(故需要注意判断读取的字符串是运算符还是数值) 可支持浮点型数据,负数, 整型数据的运算 float EvaluateEx ...
- 栈的应用(递归:例子裴波那契数列 四则运算表达式求值 :后缀(逆波兰) )
递归: -栈有一个很重要的应用:在程序设计语言中实现递归. 当你往镜子前面一站,镜子里面就有-一个你的像. 但你试过两面镜子一起照吗?如果A.B两面镜子相互面对面放着,你往中间- -站,嘿,两面镜子里 ...
- 四则运算表达式求值の各种心碎
实验三---四则运算表达式求值 一.基本要求: ( 1 ) 利用二叉树后序遍历来实现表达式的转换,同时可以使用实验三的结果来求解后缀表达式的值. ( 2) 输入输出格式: 输入格式:在字符界面上输入一 ...
- Bailian4132 四则运算表达式求值【文本处理】
4132:四则运算表达式求值 总时间限制: 1000ms 内存限制: 65536kB 描述 求一个可以带括号的小学算术四则运算表达式的值 输入 一行,一个四则运算表达式.''表示乘法,'/'表示除法 ...
- 分别用C++和JavaScript 实现四则运算表达式求值
博主16年4.19去面腾讯实习生,其中一个问题是让写一个函数求四则运算表达式的值,输入是字符串,输出为表达式结果.当时只记得这是数据结构里堆栈的应用,表达式要变顺序,但是实现就想不起来了,自然程序写的 ...
- 栈与队列及其应用 - 1.算术表达式求值
使用到了ArrayDeque集合:使用ArrayDeque表示Queue比LinkedList.表示Stack效率更高 ArrayDeque使用详解 package com.kiger.Demo;im ...
- 中缀表达式求值 Java
什么是中缀表达式: 中缀表达式的计算逻辑: 例:(10+20/2*3)/2+8 我们要按照四则运算的逻辑进行计算: (1)先计算括号内的计算单元,而内部的计算单元必须要按照四则运算的优先级来进行即先乘 ...
- 四则运算表达式求值(栈的应用)
1.前/中/后缀表达式的转换(首先需要明白三者之间的转换) 自然表达式转换为前/中/后缀表达式,其实是很简单的.首先将自然表达式按照优先级顺序,构造出与表达式相对应的二叉树,然后对二叉树进行前/ ...
- 【Leetcode栈与队列】150. 逆波兰表达式求值(后缀表达式求值,看作对对碰游戏)
文章目录 Leetcode150 1.问题描述 2.解决方案 3.计算机的思考方式 Leetcode150 1.问题描述 2.解决方案 1.逆波兰表达式优点 2.逆波兰表达式相当于是二叉树中的后序遍历 ...
最新文章
- android radiobutton 分组,Android 第十课——UI RadioButton
- android开发之svg全面总结
- 聚焦 AI + 大数据全球视野引领行业创新升级
- 阿里云正式推出高防DDoS专家服务
- SFTP是什么?与FTP之间有什么区别
- 合泰单片机c语言halt指令,holtek单片机图文全面详解
- 《高效能人士的7个习惯》读后摘记
- 变频器按启动没反应_ABB变频器启动无反应维修那些事
- MYSQL数据库SQL语句练习实验 EXERCISES. 1 SIMPLE COMMANDS
- C语言之联合与变体记录
- PHP保存图片并且修改图片分辨率(DPI)
- 360怎么修改域名服务器地址,怎样修改DNS地址
- typecho添加html5视频播放器,DPlayer-Typecho视频播放插件
- python按钮点击事件wx_wx.python事件的绑定
- Selenium面试问题及答案30题版
- 超声波清洗机是什么?
- 华为实验跨交换机不同vlan通信
- android adb 模拟长按,adb 模拟长按电源键
- Discrete regularity for graph Laplacians --Jeff Calder 读书笔记 part1 待更
- java-php-python-springboot志愿者服务平台计算机毕业设计