逆波兰表示法

逆波兰表达式(栈) 阅读详情

前言:

在逆波兰记法中,操作符置于操作数的后面。例如表达“三加四”时,写作“3 4 +”,而不是“3 + 4”。如果有多个操作符,操作符置于第二个操作数的后面,所以常规中缀记法的“3 - 4 + 5”在逆波兰记法中写作“3 4 - 5 +”:先3减去4,再加上5。使用逆波兰记法的一个好处是不需要使用括号。例如中缀记法中“3 - 4 * 5”与“(3 - 4)*5”不相同,但后缀记法中前者写做“3 4 5 * -”,无歧义地表示“3 (4 5 *) −”;后者写做“3 4 - 5 *”。

逆波兰表达式的解释器一般是基于堆栈的。解释过程一般是:操作数入栈;遇到操作符时,操作数出栈,求值,将结果入栈;当一遍后,栈顶就是表达式的值。因此逆波兰表达式的求值使用堆栈结构很容易实现,和能很快求值。

伪代码

  • while有输入符号
    • 读入下一个符号
    • IF是一个操作数
      • 入栈
    • ELSE IF是一个操作符
      • 有一个先验的表格给出该操作符需要n个参数
      • IF堆栈中少于n个操作数
        • (错误) 用户没有输入足够的操作数
      • Else,n个操作数出栈
      • 计算操作符。
      • 将计算所得的值入栈
  • IF栈内只有一个值
    • 这个值就是整个计算式的结果
  • ELSE多于一个值
    • (错误) 用户输入了多余的操作数

例子

中缀表达式“5 + ((1 + 2) * 4) − 3”写作

5 1 2 + 4 * + 3 −

下表给出了该逆波兰表达式从左至右求值的过程,堆栈栏给出了中间值,用于跟踪算法。

输入 操作 堆栈 注释
5入栈5
1入栈5, 1
2入栈5, 1, 2
+加法运算5, 3(1, 2)出栈;将结果(3)入栈
4入栈5, 3, 4
*乘法运算5, 12(3, 4)出栈;将结果(12)入栈
+加法运算17(5, 12)出栈;将结果 (17)入栈
3入栈17, 3
−减法运算14(17, 3)出栈;将结果(14)入栈

计算完成时,栈内只有一个操作数,这就是表达式的结果:14

public class Solution {
	
	public static void main(String[] args){
		String[] RPN = "5 1 -".split(" ");
		System.out.println(new Test().calculateRPN(RPN));
	}
	
	public double calculateRPN(String[] RPN) {
		assert (RPN != null && RPN.length != 0);
		Stack<Double> stack = new Stack<Double>();
		for (int i = 0; i < RPN.length; i++) {
			if (isNumber(RPN[i])) {
				stack.push(Double.parseDouble(RPN[i]));
			} else {
				double v1 = stack.pop();
				double v2 = stack.pop();
				double result = eval(RPN[i], v2, v1);
				stack.push(result);
			}
		}
		return stack.pop();
	}
	
	public boolean isNumber(String s) {
		if (s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) return false;
		return true;
	}
	
	public static double eval(String op, double val1, double val2) {
        if (op.equals("+")) return val1 + val2;
        if (op.equals("-")) return val1 - val2;
        if (op.equals("/")) return val1 / val2;
        if (op.equals("*")) return val1 * val2;
        throw new RuntimeException("Invalid operator");
    }
}

逆波兰式的实现

在逆波兰式的实现中,最大的问题是如何改变运算符的先后顺序,把高优先级的运算符放在低优先级运算符的左侧。比如,有一个中缀表达式2 + 3 × 4,它所对应的逆波兰式应当是2 3 4 × +。在我们做中缀表达式到逆波兰式转换的时候,必须在不改变操作数顺序的情况下,把高优先级的乘法操作符移动到低优先级的加法运算符的左侧。

 

很自然的,我们会想到堆栈。堆栈具有后进先出的特点。所以我们可以设计一个符号栈,用于临时存储一个中缀表达式中的全部运算符;设计一个RPN数组,用于存储逆波兰式输出。然后从左向右扫描一个中缀表达式,并循环执行以下步骤:

1. 如果扫描到一个运算数,则将其放到RPN数组的末尾

2. 如果扫描到一个运算符。首先比较该运算符和符号栈栈顶运算符的优先级。如果符号栈栈顶运算符的优先级比较低,则将新运算符压入符号栈(这样最后将符号出栈时,高优先级符号先出栈)。如果栈顶符号的优先级更高,就把栈顶符号弹出,并放入RPN数组末尾。然后继续比较新扫描到的运算符和栈顶运算符的优先级,直到找到一个优先级比自己低的栈顶元素或者到达堆栈栈底。

3. 如果表达式扫描结束。将栈中操作符顺序弹出放到RPN数组中。这样就得到了一个逆波兰表达式。

 

如下是一个逆波兰式生成过程的实例。其中绿色部分代表每一步中发生变化的部分。其中特殊之处在于对括弧的处理,括弧的优先级高于所有操作符,但是括弧中所有的操作符优先级又高于括弧。所以当栈顶为括弧的时候,不会将括弧弹出,而是继续压栈。当弹出括弧的时候,也不会把括弧放入逆波兰式中。

 

原中缀表达式:3 + 4 × (5 - 2)/ 2

逆波兰表达式:3 4 5 2 - × 2 / +

public class Test {
	public List<String> toPostfix(String[] in, HashMap<String, Integer> precedence) {
		List<String> RPN = new ArrayList<String>();  
		Stack<String> ops = new Stack<String>();
		  
		for (int i = 0; i < in.length; i++) {
			String s = in[i];
			if (!precedence.containsKey(in[i])) {
				RPN.add(s);
				continue;
			} 
			
			while(true) {
				if (ops.isEmpty() || s.equals("(") || (precedence.get(s) > precedence.get(ops.peek()))) {  
                    ops.push(s);  
                    break;  
                }
				String op = ops.pop();
				if (op.equals("(")) {
					break;
				} else {
					RPN.add(op);
				}
			}
		}
		while (!ops.isEmpty()) {
			RPN.add(ops.pop());
		}
		return RPN;
	}
	
	public HashMap<String, Integer> priorityInfo(){
        // precedence order of operators
        HashMap<String, Integer> precedence = new HashMap<String, Integer>();
        precedence.put("(", 0);   // for convenience with algorithm
        precedence.put(")", 0);  
        precedence.put("+", 1);   // + and - have lower precedence than * and /
        precedence.put("-", 1);
        precedence.put("*", 2);
        precedence.put("/", 2);
        
        return precedence;
    }
}

本文文字解释和图片来自WIKI和http://blog.youkuaiyun.com/jiangwlee/article/details/7182537

后缀表达式求值 本文章主要研究后缀表达式的求值,如何将中缀表达式转为后缀表达式等 阅读详情

相关推荐

逆波兰算法(后缀表达式)实现数学表达式计算

逆波兰算法(Reverse Polish Notation, RPN)

Gmsisxb的博客 1075

逆波兰表达式(后缀表达式)

目录啊一、什么是逆波兰表达式?二、中缀表达式转后缀表达式三、代码实现后缀表达式的计算 一、什么是逆波兰表达式? 逆波兰表达式又叫做后缀表达式。逆波兰表示法是波兰逻辑学家J・卢卡西维兹(J・ Lukasiewicz)于1929年首先提出的一种表达式的表示方法 。后来,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。(摘自百度百科) 我们再来看看什么是中缀表达式…其实。中缀表达式就是我们平时书写的数学表达式。比如: 2 + 3 * 5 ( 2 + 3 )

就这样吧 1万+

实现逆波兰表示法算法的 JavaScript 代码

逆波兰表示法(Reverse Polish Notation,简称RPN)是一种数学表达式的写法,它的特点是将运算符放在操作数的后面,使得表达式更加简洁和易于计算。本文将介绍如何使用 JavaScript 实现逆波兰表示法算法,并提供相应的源代码。通过这篇文章和相应的源代码,你可以了解如何使用 JavaScript 实现逆波兰表示法算法,并将中缀表达式转换为后缀表达式,再根据后缀表达式进行计算。逆波兰表示法算法主要涉及两个步骤:将中缀表达式转换为后缀表达式,并根据后缀表达式进行计算。

CodeWhizZ的博客 145

【数据结构】——逆波兰表达式

逆波兰表达式简介 假设有一天赵地佐同学(名称纯属虚构,如有雷同,纯属巧合)拿着一道数据极其恐怖的四则运算题找到同班的张三同学,希望他在1s内能给出答案。这时最好的办法是什么呢?当然是不理他,可惜乐于探究的张三同学并不愿意放弃这个机会,于是他拿出了随身携带的笔记本电脑。 为了解决这个问题,让我们尽可能抽象一下四则运算的表达式: ans=A+B/C+(D*E+F)*G 像上面这种符合人们认知习惯自然书写而成的数学表达式称为中缀表达式。但可惜的是,愚蠢的计算...

m0_52447591的博客 1万+

机器学习发展历史及现状(重要的期刊,会议,大牛总结)

1 引言 机器学习是指通过计算机学习数据中的内在规律性信息,获得新的经验和知识,以提高计算机的智能性,使计算机能够像人那样去决策。随着各行业对数据的需求量增多,对处理和分析数据的效率要求变高,一系列机器学习算法应运而生。机器学习算法主要是指通过数学及统计方法求解最优化问题的步骤和过程。针对不同的数据和不同模型需求,选择和使用适当的的机器学习算法可以更高效地解决一些实际问题。本文将从机器学习的起源...

Oscar2018的博客 5万+

用逐飞STC32G库做个智能小车:编码器测速、PWM调电机、ADC读电池电压(完整项目)

本文详细介绍了如何使用逐飞科技的STC32G12K128开源库构建智能小车项目,涵盖编码器测速、PWM电机控制和电池电压监测等核心功能。通过硬件选型、开发环境搭建、代码实现及调试技巧的全流程讲解,帮助开发者快速掌握基于STC32G的嵌入式系统开发,实现高性能的智能小车控制。

weixin_42526417的博客 196

C语言实现逆波兰表示法(栈)

逆波兰表示法的概念 逆波兰表示法是一种将运算符写在操作数后面的描述程序( 算式 )的方法。举个例子,我们平常用中缀表示法描述的算式( 1 +2 ) * ( 5+ 4 ),改为逆波兰表示法之后则是12 + 54 +*。相较于中缀表示法,逆波兰表示法的优势在于不需要括号 实现过程 主要使用了栈的数据结构 现在我有式子 12 + 54 +* ,1 2先压入栈,遇到运算符后,把 1 2取出来,用遇到的运算符进行运算,1 + 2 = 3;再把3压入里面,在压5 4,遇到运算符+后 取出5 4 进行运算,得 9

qq_44857505的博客 6384

校园网改造实录:手把手教你用华为MA5800 OLT调试全光网(附常用排错命令)

本文详细记录了校园全光网改造中华为MA5800 OLT的部署与调试过程,涵盖设备选型、基础配置、ONU批量部署及高频故障排查。通过实战案例和排错命令,帮助网络工程师快速掌握全光网调试技巧,实现低延迟、高稳定的网络性能。

weixin_42552716的博客 573

波兰表示法与逆波兰表示法

身为初学者,能力有限,知识尚少,如有纰漏,还望海涵。   对于表达式,通常有三种表示方法,前、中、后缀表示法。我们日常使用的数学算式就是中缀表示法。例:1+5*10-10/2 码文不易,希望支持,谢谢-&gt;支持原创 &nbsp;波兰表示法   波兰表示法(Polish notation,或波兰记法),是一种逻辑、算术和代数表示方法,其特点是操作符置于操作数...

Paradox 3849

ANSYS Fluent DPM实战:从单点到锥形注入的粒子模拟全流程解析

本文深度解析了ANSYS Fluent中离散相模型(DPM)的粒子注入(Injection)设置全流程。从单点注入到锥形喷雾,详细阐述了不同注入类型的物理本质、参数逻辑与适用场景,并提供了粒径分布、湍流扩散等高级参数设置技巧与实战避坑指南,帮助工程师精准模拟喷雾、粉尘等粒子运动行为。

weixin_29276847的博客 657

ollama接入图像识别大模型

ollama接入图像识别大模型

qq_36437991的博客 2075

算法:逆波兰表示法

逆波兰表示法 根据逆波兰表示法,求表达式的值。 有效的运算符包括+,-,*,/。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 说明: 整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。 示例1: 输入: ["2", "1", "+", "3", "*"] 输出: 9 解释: ((2 + 1) * 3)...

smarryw的博客 910

五大经典遥感数据集对比:LoveDA、Potsdam、Toronto、Vaihingen、Massachusetts Roads选哪个?

本文深度对比了LoveDA、Potsdam、Vaihingen、Toronto和Massachusetts Roads五大经典遥感数据集。针对城市监测、道路提取、土地分类等不同任务,从分辨率、标注质量、数据规模及场景多样性等核心维度进行分析,为研究者根据项目目标、硬件条件与应用场景选择最合适的遥感数据集提供决策指南。

weixin_29057065的博客 237

逆波兰表示法——栈

什么是逆波兰表示法? 逆波兰表示法是一种将运算符写在操作数后面的描述程序(算式)的方法。 举个例子,我们平常用中缀表示法描述的算式(1 + 2)* (5+ 4),改为逆波兰表示法之后则是1 2 + 3 4 - *。 相较于中缀表示法,逆波兰表示法的优势在于不需要括号。   给定一个逆波兰表达式,试求其值并输出。 思路: 将这个逆波兰表达式(说白了就是字符串)存入strinng str...

Patience 1674

智能筛选栏 SmartFilterBar 全面解析与实战指南

SmartFilterBar 把复杂的检索界面“模板化”,让开发者聚焦业务逻辑与后端数据质量,而非 UI 小细节。通过精准运用 CDS 注解与 OData 元数据,它能在几毫秒内拼装出专业级筛选体验;结合事件钩子与控制配置,又足以满足极端个性化需求。拥抱 SmartFilterBar,意味着在 Fiori 生态中以最少代码赢得最快价值交付——这正是现代企业应用开发追求的极致效率。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 404

机器人视觉仿真软件:PCL (Point Cloud Library)_(8).点云分割技术

点云分割技术在机器人视觉处理中起着至关重要的作用,通过不同的分割方法可以有效地将点云数据中的不同物体或区域分离出来。PCL提供了丰富的分割算法,包括基于平面的分割、基于聚类的分割、基于模型的分割和基于条件的分割等。每种方法都有其适用的场景和优缺点,选择合适的方法可以显著提高点云处理的效率和准确性。希望本节的内容能够帮助读者更好地理解和应用点云分割技术。

kkchenjj的博客 822

逆波兰表示法(Reverse Polish Notation)

翻译自Harley Hahn's Guide to Unix and Linux 最 初,bc这个程序是基于dc(desk calculator)程序开发的. dc是最古老的Unix程序之一,它的出现甚至比C语言还要早. 事实上, dc的最初版本是在1970年用C语言的祖先即B语言编写的. 我们待会将讨论bc和dc之间的联系. 但现在我想告诉你的是关于dc的一些知识. dc本身就是一个很有趣的工

linuxdashencom的博客 1004

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

波兰表示法和逆波兰表示法的转换

笔试题算法实现 最近有很多笔试算法题,碰到了一道很陌生的:波兰表示法和逆波兰表示法的转换,用java代码实现了一下,题解给的实例跑通了,不知道其他的怎么样。 题干如下: 思路 从后向前遍历输入的字符数组 根据题干中前波的表示方法入栈 输出前波的结果,与给出示例表达式对比 *将正确的前波拆分入栈 规则为遇到右括号出栈四项值,分别为:左括号,表达式左值,表达式,表达式右值 按后波的规则拼接...

ahienoq190204的博客 326

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

逆波兰表示法与冯诺依曼自动机。

冯诺依曼自动机的原理就是:两个队列,一个是操作队列,另一个是数据队列;操作队列消耗数据,导致数据队列变短,同时产生结果;理想状况是,操作队列与数据队列同时清空,这样就可以直接开始下一个任务。显然,冯诺依曼自动机是一个自动计算模型。 逆波兰表示法是完全遵从冯诺依曼自动机原理设计的四则运算解算模型。它的要求是:计算符号(±/不包括括号)与数据分别入栈,使用时顺次取出符号与数据,从而实现连续计算。比如:%.1 + %.2 * ( %.3 - %.4 )用逆波兰表示法,符号队列是-+,数据队列是%.3, %.4,

luj_1768的博客 148

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

后缀表达式求值:逆波兰表示法完整指南

后缀表达式(Reverse Polish Notation,RPN)是一种高效的数学表达式计算方法,无需括号即可明确运算顺序。本文将通过GitHub加速计划的C语言实现项目,带你掌握从表达式转换到求值的完整流程,轻松解决复杂运算问题。 ## 什么是逆波兰表示法? 逆波兰表示法将运算符置于操作数之后,例如"3 4 +"表示3+4。这种结构天然符合栈式计算逻辑,避免了中缀表达式中括号的复杂性。项目

gitblog_00545的博客 999
上一篇: 01背包问题
下一篇: 版本号比较
beiyetengqing
博客等级 码龄14年 148粉丝 169原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值