036 前缀 中缀 后缀(逆波兰表达式)表达式

前缀表达式

前缀表达式(波兰表达式)

  1. 前缀表达式又称波兰表达式,前缀表达式的运算符位于操作数之前
  2. 举例说明:(3 + 4) * 5 -6 对应的前缀表达式就是 - * + 3 4 5 6

前缀表达式课计算机求值

从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 和 次顶元素),并将结果入栈;重复上述过程直到表达式的最左端,最后运算出的值即为表达式的结果

例如:(3 + 4) * 5 -6 应的前缀表达式就是 - * + 3 4 5 6
步骤如下:

  1. 从右至左扫描,将 6、5、4、3压入堆栈
  2. 遇到 + 运算符,因此 弹出3和4(3为栈顶元素,4为次顶元素),计算出 3+4 的值,得7,再将7入栈
  3. 接下来是 * 运算符,因此弹出 7 和 5,计算出 7 * 5 = 35 ,将35入栈
  4. 最后是 - 运算符,计算出 35 - 6 的值,即 29,由此得出最终的结果

中缀表达式

  1. 中经表达式就是最常见的运算表达式,如:(3 + 4) * 5 -6
  2. 中缀表达式的求值是我们人最熟悉的,但是对计算机来说却不好操作(前面我们讲的案例就能看到这个问题),因此,在计算结果时,往往会将中缀表达式转成其它表达式来操作(一般转成后缀表达式)

后缀表达式

  1. 后缀表达式又称逆波兰表达式与前缀表达式相似,只是运算符位于操作数之后
  2. 举例说明: (3 + 4) * 5 -6 对应的后缀表达式就是:3 4 + 5 * 6 -
正常的表达式 逆波兰表达式
a + b a b +
a + (b - c) a b c - +
a + (b - c) * d a b c - d * +
a + d * (b - c) a d b c - * +
a = 1 + 3 a 1 3 + =

正常表达式转为后缀表达式的规律:(盲猜)
数字从左向右提取,符号从右向左取;但是先取优先级高的,再取优先级低的。(还是有些不对)

后缀表达式的计算机求值过程

从左至右扫描表达式,遇到数字时,将数字夺入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和栈顶元素),并将结果入栈;重复上述过程直到表达式的最右端,最后运算得出的值即为表达式的结果

例如:(3 + 4) * 5 - 6 对应的前缀表达式就是 3 4 + 5 * 6 ,针对后缀表达式求值步骤如下:

  1. 从左至右扫描,将 3 和 4 压入堆栈
  2. 遇到 + 运算符,因此弹出 4 和 3 (4 为栈顶元素, 3 为次顶元素),计算出 3 + 4 的值,得7,再将 7 入栈
  3. 将 5 入栈
  4. 接下来是 * 运算符,因此弹出 5 和 7 ,计算出 7 * 5 = 35 ,将 35 入栈
  5. 将 6 入栈
  6. 最后是 - 运算符,计算出 35 - 6 的值,即 29 ,由此得出最终结果

037-038 逆波兰计算器分析和实现

完成一个逆波兰计算器,

  1. 输入一个逆波兰表达式,使用栈(stack),计算其结果
  2. 支持小括号和多位整数,因为主讲数据结构,因此简化, 只支持整数的计算
package com.old.stack_036_042;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;public class PolandNotation {public static void main(String[] args) {/*先定义一个逆波兰表达式(3 + 4) * 5 - 6 => 3 4 + 5 x 6 -说明:为了方便,逆波兰表达式的数字和符号使用空格隔开*/String suffixExpression = "30 4 + 5 * 6 -";/*** 思路:* 1. 先将  "3 4 + 5 x 6 -" 放到 ArrayList 中* 2. 将 ArrayList 传递给一个方法,遍历 ArrayList 配合栈完成计算* 将他放入list中的好处是方便取,不然还需要使用 index 取太累了*/List<String> list = getList(suffixExpression);// [3, 4, +, 5, x, 6, -]System.out.println(list.toString());//计算对逆波兰表达式的运算int res = calculate(list);System.out.println("结果:" + res);}/*1. 从左至右扫描,将 3 和 4 压入堆栈2. 遇到 + 运算符,因此弹出 4 和 3 (4 为栈顶元素, 3 为次顶元素),计算出 3 + 4 的值,得7,再将 7 入栈3. 将 5 入栈4. 接下来是 \* 运算符,因此弹出 5 和 7 ,计算出 7 \* 5 = 35 ,将 35 入栈5. 将 6 入栈6. 最后是 - 运算符,计算出 35 - 6 的值,即 29 ,由此得出最终结果*/public static int calculate(List<String> ls){//创建栈,只需要一个栈即可Stack<String> stack = new Stack<>();//遍历 lsfor (String item : ls) {//这里使用正则表达式取出数//匹配的是多位数if (item.matches("\\d+")) {//如果是数,直接入栈stack.push(item);}else {int num2 = Integer.valueOf(stack.pop());int num1 = Integer.valueOf(stack.pop());int res = 0;if (item.equals("+")){res = num1 + num2;}else if (item.equals("-")){// - 和 除的顺序有要求res = num1 - num2;}else if (item.equals("*")){// - 和 除的顺序有要求res = num1 * num2;}else if (item.equals("/")){// - 和 除的顺序有要求res = num1 / num2;}else {throw new RuntimeException("运算符有误");}stack.push(res + "");}}//最后留在 stack 中的数据就是运算结果return Integer.valueOf(stack.pop());}/*** 将一个逆波兰表达式,依次将数据和运算符,放入到 ArrayList中*/public static List<String> getList(String suffixExpression){return new ArrayList<>(Arrays.asList(suffixExpression.split(" ")));}
}

039-042 中缀表达式转后缀表达式

039 思路解析

这里是将表达式进行转换,而不是计算结果
(个人看法:不管是前缀、中缀、后缀,哪种表达式,他的规律或者说的他其实就是中缀表达式按照要求入栈的顺序)前缀:从右至左扫描表达式。后缀:从左至右扫描
中缀表达式转换炎后缀表达式
后缀表达式适合计算机进行运算,但是人却不太容易写出来,尤其是表达式很长的情况下
具体步骤:

  1. 初始化两个栈:运算符栈 s1 和 储存中间结果的栈 s2
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数时,将其压 s2
  4. 遇到运算符时,比较其与 s1 栈顶运算符的优先级:
    1. 如果 s1 为空,或栈顶运算符为 左括号“(” ,则直接将运算符入栈
    2. 否则,若优先级比栈顶运算符的高,也将运算符压入 s1
    3. 否则,将 s1 栈顶的运算符弹出并压入 s2 中,再次转到 4-1操作 与 s1 中新的栈顶运算符相比较

040 代码实现1

package com.old.stack_036_042;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;public class PolandNotation {public static void main(String[] args) {/*** 将中缀表达式转为后缀表达式的结果* 1. 1 + ((2 + 3) * 4) - 5 => 1 2 3 4 * + 5* 2. 因为直接对一个字符串进行操作,不太方便,因此,先将 “1 + ((2 + 3) * 4) - 5” 中经表达式转为对应的list*  即,将 “1 + ((2 + 3) * 4) - 5” =》 ArrayList 【1,+,(】*/String expression = "1 + ((2 + 3) * 4) - 5";List<String> infixExpressionList = toInfixExpressionList(expression);System.out.println(infixExpressionList);/*先定义一个逆波兰表达式(3 + 4) * 5 - 6 => 3 4 + 5 x 6 -说明:为了方便,逆波兰表达式的数字和符号使用空格隔开*/String suffixExpression = "30 4 + 5 * 6 -";/*** 思路:* 1. 先将  "3 4 + 5 x 6 -" 放到 ArrayList 中* 2. 将 ArrayList 传递给一个方法,遍历 ArrayList 配合栈完成计算* 将他放入list中的好处是方便取,不然还需要使用 index 取太累了*/List<String> list = getList(suffixExpression);// [3, 4, +, 5, x, 6, -]System.out.println(list.toString());//计算对逆波兰表达式的运算int res = calculate(list);System.out.println("结果:" + res);}/*** 40P 新增代码* 将 中缀表达式转成对应的List* @param s* @return*/public static List<String> toInfixExpressionList(String s){s = s.trim();List<String> ls = new ArrayList<>(s.length());//这是指针,用于遍历中缀表达式字符串int i = 0;//对多位数的拼接String str;//每遍历一个字符,就放入 cchar c;do {if (" ".equals(s.substring(i, i + 1))){i++;continue;}//如果 c 是一个非数字,就放入到 cif ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57){ls.add(c + "");i++;}else {//如果是一个数,需要考虑多位数的问题//先将 str 置为空字符串str = "";while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57){str += c;i++;}ls.add(str);}}while (i < s.length());return ls;}/*1. 从左至右扫描,将 3 和 4 压入堆栈2. 遇到 + 运算符,因此弹出 4 和 3 (4 为栈顶元素, 3 为次顶元素),计算出 3 + 4 的值,得7,再将 7 入栈3. 将 5 入栈4. 接下来是 \* 运算符,因此弹出 5 和 7 ,计算出 7 \* 5 = 35 ,将 35 入栈5. 将 6 入栈6. 最后是 - 运算符,计算出 35 - 6 的值,即 29 ,由此得出最终结果*/public static int calculate(List<String> ls){//创建栈,只需要一个栈即可Stack<String> stack = new Stack<>();//遍历 lsfor (String item : ls) {//这里使用正则表达式取出数//匹配的是多位数if (item.matches("\\d+")) {//如果是数,直接入栈stack.push(item);}else {int num2 = Integer.valueOf(stack.pop());int num1 = Integer.valueOf(stack.pop());int res = 0;if (item.equals("+")){res = num1 + num2;}else if (item.equals("-")){// - 和 除的顺序有要求res = num1 - num2;}else if (item.equals("*")){// - 和 除的顺序有要求res = num1 * num2;}else if (item.equals("/")){// - 和 除的顺序有要求res = num1 / num2;}else {throw new RuntimeException("运算符有误");}stack.push(res + "");}}//最后留在 stack 中的数据就是运算结果return Integer.valueOf(stack.pop());}/*** 将一个逆波兰表达式,依次将数据和运算符,放入到 ArrayList中*/public static List<String> getList(String suffixExpression){return new ArrayList<>(Arrays.asList(suffixExpression.split(" ")));}
}

041

package com.old.stack_036_042;import com.sun.org.apache.regexp.internal.RE;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;public class PolandNotation {public static void main(String[] args) {/*** 将中缀表达式转为后缀表达式的结果* 1. 1 + ((2 + 3) * 4) - 5 => 1 2 3 4 * + 5* 2. 因为直接对一个字符串进行操作,不太方便,因此,先将 “1 + ((2 + 3) * 4) - 5” 中经表达式转为对应的list*  即,将 “1 + ((2 + 3) * 4) - 5” =》 ArrayList 【1,+,(】* 3. 将得到的中缀表达式对应的 list =》 后缀表达式对应的 list* 1 2 3 4 * + 5*/String expression = "1 + ((2 + 3) * 4) - 5";List<String> infixExpressionList = toInfixExpressionList(expression);System.out.println(infixExpressionList);List<String> suffixExpressionList = parseSuffixExpressionList(infixExpressionList);System.out.println(suffixExpressionList);//计算对逆波兰表达式的运算int res = calculate(suffixExpressionList);System.out.println("结果:" + res);}/*** 将得到的中缀表达式对应的 list =》 后缀表达式对应的 list** @param ls* @return*/public static List<String> parseSuffixExpressionList(List<String> ls) {//定义两个栈,初始化栈//符号栈Stack<String> s1 = new Stack<>();/*** 存储中间结果的线* 说明:因为 s2 这个栈,在整个转换过程中,没有 pop 操作,而且后面还需要* 逆序输出。比较麻烦,所以这里使用 数组,不使用栈*         Stack<String> s2 = new Stack<>();*///储存中间结果List<String> s2 = new ArrayList<>();for (String item : ls) {//如果是一个数,入栈 s2if (item.matches("\\d+")){s2.add(item);}else if (item.equals("(")){s1.push(item);}else if (item.equals(")")){/*如果是右括号“)”,则依次弹出 s1 栈顶的运算符,并压入 s2,直到遇到左括号为止,此时将这一对括号丢弃*/while (!s1.peek().equals("(")){s2.add(s1.pop());}//将 “(” 弹出栈s1.pop();/*这个循环会将for (String s : s1) {if (s.equals("(")){break;}s2.add(s);}*/}else {/*当 item 的优先级 小于等于 栈顶的运算符 ,将 s1 栈顶的运算符弹出并加入到 s2 中,再次转到 (4.1步骤)与 s1 中新的栈顶运算符相比较缺少一个比较优先级高低的方法*/while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){s2.add(s1.pop());}//还需要将 item 压入栈中s1.push(item);}}//将 s1 中剩余的运算符依次弹出 并加入 s2while (s1.size() != 0){s2.add(s1.pop());}//注意:因为是存入到 List 中,因此按顺序输出,就是对应的后缀表达式对应的listreturn s2;}/*** 将 中缀表达式转成对应的List** @param s* @return*/public static List<String> toInfixExpressionList(String s) {s = s.trim();List<String> ls = new ArrayList<>(s.length());//这是指针,用于遍历中缀表达式字符串int i = 0;//对多位数的拼接String str;//每遍历一个字符,就放入 cchar c;do {if (" ".equals(s.substring(i, i + 1))) {i++;continue;}//如果 c 是一个非数字,就放入到 cif ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57) {ls.add(c + "");i++;} else {//如果是一个数,需要考虑多位数的问题//先将 str 置为空字符串str = "";while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57) {str += c;i++;}ls.add(str);}} while (i < s.length());return ls;}/*1. 从左至右扫描,将 3 和 4 压入堆栈2. 遇到 + 运算符,因此弹出 4 和 3 (4 为栈顶元素, 3 为次顶元素),计算出 3 + 4 的值,得7,再将 7 入栈3. 将 5 入栈4. 接下来是 \* 运算符,因此弹出 5 和 7 ,计算出 7 \* 5 = 35 ,将 35 入栈5. 将 6 入栈6. 最后是 - 运算符,计算出 35 - 6 的值,即 29 ,由此得出最终结果*/public static int calculate(List<String> ls) {//创建栈,只需要一个栈即可Stack<String> stack = new Stack<>();//遍历 lsfor (String item : ls) {//这里使用正则表达式取出数//匹配的是多位数if (item.matches("\\d+")) {//如果是数,直接入栈stack.push(item);} else {int num2 = Integer.valueOf(stack.pop());int num1 = Integer.valueOf(stack.pop());int res = 0;if (item.equals("+")) {res = num1 + num2;} else if (item.equals("-")) {// - 和 除的顺序有要求res = num1 - num2;} else if (item.equals("*")) {// - 和 除的顺序有要求res = num1 * num2;} else if (item.equals("/")) {// - 和 除的顺序有要求res = num1 / num2;} else {throw new RuntimeException("运算符有误");}stack.push(res + "");}}//最后留在 stack 中的数据就是运算结果return Integer.valueOf(stack.pop());}/*** 将一个逆波兰表达式,依次将数据和运算符,放入到 ArrayList中*/public static List<String> getList(String suffixExpression) {return new ArrayList<>(Arrays.asList(suffixExpression.split(" ")));}
}//编写一个类,Operation 可以返回一个运算符对应的优先级
class Operation{//+private static int ADD = 1;//-private static int SUB = 1;//*private static int MUL = 2;// 除/private static int DIV = 2;//写一个方法,返回对应的优先级数字public static int getValue(String operation){int result = 0;switch (operation){case "+":result = ADD;break;case "-":result = SUB;break;case "*":result = MUL;break;case "/":result = DIV;break;}return result;}
}

数组结构与算法-036-042 前中后缀表达式-逆波兰计算器相关推荐

  1. 栈结构应用_普通计算器和逆波兰计算器

    栈的运用--普通计算器和逆波兰计算器 用栈实现计算器,这个比较难.有兴趣和热情的朋友,你可以看看.没有的,建议你看下一个数据结构. 逆波兰计算器是我们的终极目标,在实现目标之前,需要不断积累,所以我们 ...

  2. 【数据结构与算法篇】什么是后缀表达式?

    什么是后缀.前缀.以及中缀表达式呢?他与我们平时在数学中见到的表达式有什么区别?第一次看这个名词,我还是有点蒙,难理解,所以做以下笔记,以便日后复习,也希望可以帮助读者,以相互促进. 文章目录 前言: ...

  3. 数据结构与算法——前缀、中缀、后缀表达式

    目录 一.前缀表达式(波兰表达式) 二.中缀表达式 三.后缀表达式(逆波兰表达式) 1.逆波兰计算器 四.中缀转后缀 1.具体步骤 2.代码实现 一.前缀表达式(波兰表达式) 前缀表达式的运算符位于操 ...

  4. c++获取数组长度查找算法_在C ++中查找数组长度

    c++获取数组长度查找算法 介绍 (Introduction) In this article, we are going to learn about the various ways follow ...

  5. 逆波兰计算器android源码简书,计算器的核心算法-JavaScript实现(逆波兰表达式)...

    最终计算器的掩饰效果,欢迎大家来找BUG. http://codepen.io/lvanboy/full/LxKVxJ/ 功能: 1.按照运算符的优先级运算 2.利用上次的结果继续运算 3.多个数字混 ...

  6. JavaScript数组结构与算法——数组详解(中)

    迭代器方法 在上篇中,我们探讨了很多数组方法,接下来总结一下最后一组方法--迭代器方法.这些方法对数组的每个元素应用一个函数,可以返回一个值.一组值.或者一个新数组. 1.不生成新数组的迭代器方法 以 ...

  7. 数组结构与算法-007-015稀疏数组与队列

    007 稀疏数组的应用场景 基本介绍: 当一个数组中大部分元素为0,或者为同一个数值的数组时,可以稀疏数组来保存该数组 稀疏数组的处理方法是: 记录数组一共有几行几列,有多少个不同的值 把具有不同值的 ...

  8. 前、中、后缀表达式概述及转换+栈的计算器原理及代码分析(含完整源码)

    目录: 1.前中后缀表达式的概述 2.中序表达式转前后缀表达式 3.运用栈的后缀表达式实现计算器原理步骤 4.代码实现和分析 1.前中后缀表达式的概述及相互转换 前缀表达式:运算符位于操作数之前. 中 ...

  9. 二叉树结构与算法思路解析

    二叉树 介绍 主要内容 二叉树的概念和性质 二叉树的存储结构 遍历二叉树 递归遍历 非递归遍历 线索二叉树 哈夫曼树 树和森林 树和森林的存储 树和森林与二叉树的转换 树和森林的遍历 树型结构特点 一 ...

最新文章

  1. Malformed server response 解决方案
  2. 安卓高手之路之ClassLoader(四)
  3. 线程间通信的两种方式
  4. Spring MVC中使用Swagger生成API文档和完整项目示例Demo,swagger-server-api(二十)
  5. Android 借助Stetho在Chrome上调试Android网络、数据库、Sharedpreferences
  6. Luogu 3698 [CQOI2017]小Q的棋盘
  7. Avalonia跨平台入门第十九篇之语音播放
  8. 无人驾驶的规划与控制(四)——反馈控制
  9. 合作活动 | 鲸准产业价值峰会AI专场,共探AI商业模式
  10. Retrofit的初次使用
  11. [Oracle] SQL*Loader 详细使用教程(5)- 典型例子
  12. Win7连接蓝牙4.0鼠标
  13. 【学习记录】QT5 的简单界面设计及错误总结
  14. php博饼,妙趣横生庆中秋:厦门博饼
  15. javaweb项目页面崩溃报错
  16. 苹果六电池_苹果新产品发布,这次加量不加价!
  17. 追思“光纤之父”,物理学诺贝尔奖得主高锟自述
  18. 高防ip是如何防御攻击的?
  19. html标签的多级列表,Word小技巧1:利用多级列表功能实现章节标题自动编号
  20. CSS中的绝对定位和相对定位

热门文章

  1. Hadoop源代码分析
  2. 九大遥感目标检测数据集(附下载链接)
  3. 中国医科大学22春《病理学(本科)》在线作业【标准答案】
  4. 年薪30万IT精英 挥别都市回乡种田务农
  5. 【翻译】代码指针完整性——Code Pointer Integrity
  6. UVA 10158 (记忆化搜索)
  7. 我的HTML学习(二)----html的基本分类与字符集的学习
  8. python表情换头_使用Python制作表情包实现换脸功能
  9. linux下下载fnl数据,如何下载fnl
  10. ffmpeg 常用命令总结:(avi转MP4、MP4转ts、视频压缩、去除视频声音、合并音频和视频)