前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >表达式(四则运算)计算的算法

表达式(四则运算)计算的算法

作者头像
程序员徐公
发布2018-09-18 17:33:50
2.9K0
发布2018-09-18 17:33:50
举报

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1342041

表达式(四则运算)计算的算法

戏剧前奏——基本知识点

通常我们所看到的算术表达式,运算符总是在两个操作数中间(除),如(A+B)*C,这样的表达式叫做中缀表达式。这种表达式不同的运算符优先级不同,而且通常含有括号,计算机很难理解这种表达式。在编译系统中,要把人易于理解的表达式翻译成能正确求值的机器指令。编译系统中对中缀形式的算术表达式的处理方式是: 先把中缀表达式转换成后缀表达式,再进行计算。

后缀表达式就是表达式中的运算符出现在操作数的后面,并且不含括号,如AB+C*。后缀表达式的特点:

(1).后缀表达式让操作数和中缀表达式的操作数先后次序相同,只是运算符的先后次序改变;

(2).后缀表达式没有括号,运算次序就是其执行次序。

在计算机内部,任何一个表达式都是由操作数、运算符和分界符组成。操作数和运算符是表达式的主要部分,分界符(如用#表示)标志了一个表达式的结束。我们把操作数、运算符和分界符称为表达式的单词

一个中缀表达式的四则运算规则:

1.先乘除后加减

2.先括号内后括号外

3.同级别时先左后右

下面以A+(B-C/D)*E为例对过程进行讲解。A+(B-C/D)*E转换成后缀表达式后为

ABCD/-E*+

其运算次序为:T1=CD/; T2=BT1-; T3=T2E*; T4=AT3+。

基于后缀表达式的两个特点,计算过程如下:计算时只要从左到右依次扫描后缀表达式的各个单词,当读到的单词为运算符时,就对该运算他会前两个操作数进施以此运算所代表的操作,然后将结果T插入到后缀表达式中再重复上面的操作。

享受过程——实现步骤和方法

根据以上的讲解,可初步地列出实现的步骤如下:

1.把中缀表达式的字符中提取出一系列表达式单词;

2.把中缀表达式单词系列转换成后缀表达式单词系列;

3.对后缀表达式词系列依次进行计算。

下面依次对各个步骤进行讲解。

把中缀表达式的字符中提取出一系列表达式单词

要提取表达式单词,首先要定义一个单词的类,判断该字符串是否是数字还是运算符

代码如下

代码语言:javascript
复制
<span style="color:#ff6666;">/**
	 * 判断当前字符或字符串是否是数字
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNumber(String str) {
		return str.startsWith("0") || str.startsWith("1")
				|| str.startsWith("2") || str.startsWith("3")
				|| str.startsWith("4") || str.startsWith("5")
				|| str.startsWith("6") || str.startsWith("7")
				|| str.startsWith("8") || str.startsWith("9")
				|| str.startsWith(".");

	}</span>

将算式表达式转换成操作数和运算符,放入链表中

代码语言:javascript
复制
         /**
	 * 分析四则运算表达式,将数字与运算符进行分解
	 */
	public static List<String> parse(String exp) {
		int length = exp.length();

		// 四则运算解析
		List<String> expList = new ArrayList<String>();

		String tempStr = "";
		for (int i = 0; i < length; i++) {
			String tempChar = exp.substring(i, i + 1);
			if (DataUtils.isNumber(tempChar)) {// 如果是数字的话
				tempStr += tempChar;
			} else {
				if (!tempStr.equals("")) {// 遇到运算符,判断存储的数字字符串是否为空
					expList.add(tempStr);
				}
				expList.add(tempChar);
				tempStr = "";
			}
		}
		if (!tempStr.equals("")) {// 保证最后一个非空的数字字符串添加到expList中
			expList.add(tempStr);
		}
		return expList;
	}

把中缀表达式单词系列转换成后缀表达式单词系列

中缀表达式转换成后缀表达式的算法步骤:(1).设置一个堆栈S,初始时将栈顶元素设置为#。(2).顺序读入中缀表达式,当读到的单词为操作数时将其加入到线性表L, 并接着读下一个单词。(3).令x1为当前栈顶运算符的变量,x2为当前扫描读到的运算符的变量,当顺序从中缀表达式中读入的单词为运算符时就赋予x2;然后比较x1与x2的优先级,若优先级x1>x2,将x1从S中出栈,并加入L中,接着比较新的栈顶运算符x1与x2的优先级;若优先级x1<x2,将x2入栈S,接着读下一个单词;若优先级x1=x2且x1为”(”而x2为”)”,将x1出栈,接着读下一个单词;若优先级x1=x2且x1为”#”而x2为”#”,算法结束。

各运算符优先级关系表

x2 x1

+

-

×

÷

(

)

+

<

<

<

-

<

<

<

×

<

÷

<

(

<

<

<

<

<

=

$

)

$

<

<

<

<

<

$

=

表中x1为+或-,x2为*或/时,优先级x1<x2,满足中缀表达式规则1.先乘除后加减;x1为+、-、*或/,x2为(或/时,优先级x1<x2,满足中缀表达式规则2.先括号内后括号外;当x1的运算符x2的运算符同级别时,优先级x1=x2,满足中缀表达式规则3.同级别时先左后右。出现表中的$表示中缀表达式语法出错。

中缀表达式转换成后缀的过程

步骤

中序表达式

堆栈

输出

1

A+(B-C/D)*E#

2

+(B-C/D)*E#

A

3

(B-C/D)*E#

#+

A

4

B-C/D)*E#

#+(

A

5

-C/D)*E#

#+(

AB

6

C/D)*E#

#+(-

AB

7

/D)*E#

#+(-

ABC

8

D)*E#

#+(-/

ABC

9

)*E#

#+(-/

ABCD

10

*E#

#+(-

ABCD/

11

*E#

#+(

ABCD-

12

*E#

#+

ABCD-

13

E#

#+*

ABCD-

14

#+*

ABCD-E

15

#+

ABCD-E*

16

ABCD-E*+

代码语言:javascript
复制
         /**
	 * 将分解后的四则运算列表构建成逆波兰表达式列表
	 */
	public static List<String> createRPN(List<String> expList) {
		Stack stack = new Stack();
		// 存放逆波兰表达式
		List<String> rpnList = new ArrayList<String>();

		int length = expList.size();
		for (int i = 0; i < length; i++) {
			String c = expList.get(i);

			// 如果是数字,直接放到逆波兰链表的最后
			if (DataUtils.isNumber(c)) {
				rpnList.add(c);
			} else {
				// 如果不是数字
				// 如果是左括号,则直接将左括号压入栈
				if (OperatorUtils.isParenthesesStart(c)) {
					stack.push(c);
				} else if (OperatorUtils.isParenthesesEnd(c)) {
					// 如果是右括号

					// 进行出栈操作,直到栈为空或者遇到第一个左括号
					while (!stack.isEmpty()) {
						// 将栈顶字符串做出栈操作
						String tempC = stack.pop();
						if (!tempC.equals(OperatorUtils.OPSTART)) {
							// 如果不是左括号,则将字符串直接放到逆波兰链表的最后
							rpnList.add(tempC);
						} else {
							// 如果是左括号,退出循环操作
							break;
						}
					}
				} else {
					// 如果栈内为空
					if (stack.isEmpty()) {
						// 将当前字符串直接压栈
						stack.push(c);
					} else {
						// 如果栈不为空

						// 比较栈顶字符串与当前字符串的优先级
						if (OperatorUtils.compare(stack.top(), c)) {
							// 如果栈顶元素的优先级大于当前字符串,则进行出栈操作
							// 将栈顶元素直接放到逆波兰链表的最后
							// 直到栈内为空,或者当前元素的优先级不小于栈顶元素优先级
							while (!stack.isEmpty()
									&& OperatorUtils.compare(stack.top(), c)) {
								rpnList.add(stack.pop());
							}
						}
						// 将当前字符串直接压栈
						stack.push(c);
					}
				}

			}
		}

		// 如果栈不为空,则将栈中所有元素出栈放到逆波兰链表的最后
		while (!stack.isEmpty()) {
			rpnList.add(stack.pop());
		}
		return rpnList;
	}

源码下载地址: http://download.csdn.net/detail/gdutxiaoxu/9375669 

参考地址http://blog.csdn.net/luoweifu/article/details/10477447

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015年12月24日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 戏剧前奏——基本知识点
  • 享受过程——实现步骤和方法
    • 把中缀表达式的字符中提取出一系列表达式单词
      • 把中缀表达式单词系列转换成后缀表达式单词系列
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档