Java数据结构和算法(六)——前缀、中缀、后缀表达式

Wesley13
• 阅读 500

前面我们介绍了三种数据结构,第一种数组主要用作数据存储,但是后面的两种栈和队列我们说主要作为程序功能实现的辅助工具,其中在介绍栈时我们知道栈可以用来做单词逆序,匹配关键字符等等,那它还有别的什么功能吗?以及数据结构与本篇博客的主题前缀、中缀、后缀表达式有什么关系呢?

1、人如何解析算术表达式

  如何解析算术表达式?或者换种说法,遇到某个算术表达式,我们是如何计算的:

  ①、求值 3+4-5

Java数据结构和算法(六)——前缀、中缀、后缀表达式

  这个表达式,我们在看到3+4后都不能直接计算3+4的值,知道看到4后面的 - 号,因为减号的优先级和前面的加号一样,所以可以计算3+4的值了,如果4后面是 * 或者 /,那么就要在乘除过后才能做加法操作,比如:

  ②、求值 3+4*5

Java数据结构和算法(六)——前缀、中缀、后缀表达式

  这个不能先求3+4的值,因为4后面的*运算级别比前面的+高。通过这两个表达式的说明,我们可以总结解析表达式的时候遵循的几条规则:

  ①、从左到右读取算式。

②、已经读到了可以计算值的两个操作数和一个操作符时,可以计算,并用计算结果代替那两个操作数和一个操作符。

③、继续这个过程,从左到右,能算就算,直到表达式的结尾。

2、计算机如何解析算术表达式

  对于前面的表达式 3+4-5,我们人是有思维能力的,能根据操作符的位置,以及操作符的优先级别能算出该表达式的结果。但是计算机怎么算?

  计算机必须要向前(从左到右)来读取操作数和操作符,等到读取足够的信息来执行一个运算时,找到两个操作数和一个操作符进行运算,有时候如果后面是更高级别的操作符或者括号时,就必须推迟运算,必须要解析到后面级别高的运算,然后回头来执行前面的运算。我们发现这个过程是极其繁琐的,而计算机是一个机器,只认识高低电平,想要完成一个简单表达式的计算,我们可能要设计出很复杂的逻辑电路来控制计算过程,那更不用说很复杂的算术表达式,所以这样来解析算术表达式是不合理的,那么我们应该采取什么办法呢?

  请大家先看看什么是前缀表达式,中缀表达式,后缀表达式:这三种表达式其实就是算术表达式的三种写法,以 3+4-5为例

  ①、前缀表达式:操作符在操作数的前面,比如 +-543

  ②、中缀表达式:操作符在操作数的中间,这也是人类最容易识别的算术表达式 3+4-5

  ③、后缀表达式:操作符在操作数的后面,比如 34+5-

  上面我们讲的人是如何解析算术表达式的,也就是解析中缀表达式,这是人最容易识别的,但是计算机不容易识别,计算机容易识别的是前缀表达式和后缀表达式,将中缀表达式转换为前缀表达式或者后缀表达式之后,计算机能很快计算出表达式的值,那么中缀表达式是如何转换为前缀表达式和后缀表达式,以及计算机是如何解析前缀表达式和后缀表达式来得到结果的呢?

3、后缀表达式

  后缀表达式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则)。

  由于后缀表达式的运算符在两个操作数的后面,那么计算机在解析后缀表达式的时候,只需要从左向右扫描,也就是只需要向前扫描,而不用回头扫描,遇到运算符就将运算符放在前面两个操作符的中间(这里先不考虑乘方类似的单目运算),一直运算到最右边的运算符,那么就得出运算结果了。既然后缀表达式这么好,那么问题来了:

①、如何将中缀表达式转换为后缀表达式?

  对于这个问题,转换的规则如下:

  Java数据结构和算法(六)——前缀、中缀、后缀表达式

  一、先自定义一个栈

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

package com.ys.poland;

public class MyCharStack {

private char``[] array;

private int maxSize;

private int top;

public MyCharStack(``int size){

this``.maxSize = size;

array = new char``[size];

top = -``1``;

}

//压入数据

public void push(``char value){

if``(top < maxSize-``1``){

array[++top] = value;

}

}

//弹出栈顶数据

public char pop(){

return array[top--];

}

//访问栈顶数据

public char peek(){

return array[top];

}

//查看指定位置的元素

public char peekN(``int n){

return array[n];

}

//为了便于后面分解展示栈中的内容,我们增加了一个遍历栈的方法(实际上栈只能访问栈顶元素的)

public void displayStack(){

System.out.print(``"Stack(bottom-->top):"``);

for``(``int i = 0 ; i < top+``1``; i++){

System.out.print(peekN(i));

System.out.print(``' '``);

}

System.out.println(``""``);

}

//判断栈是否为空

public boolean isEmpty(){

return (top == -``1``);

}

//判断栈是否满了

public boolean isFull(){

return (top == maxSize-``1``);

}

}

  二、前缀表达式转换为后缀表达式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

package com.ys.poland;

public class InfixToSuffix {

private MyCharStack s1;``//定义运算符栈

private MyCharStack s2;``//定义存储结果栈

private String input;

//默认构造方法,参数为输入的中缀表达式

public InfixToSuffix(String in){

input = in;

s1 = new MyCharStack(input.length());

s2 = new MyCharStack(input.length());

}

//中缀表达式转换为后缀表达式,将结果存储在栈中返回,逆序显示即后缀表达式

public MyCharStack doTrans(){

for``(``int j = 0 ; j < input.length() ; j++){

System.out.print(``"s1栈元素为:"``);

s1.displayStack();

System.out.print(``"s2栈元素为:"``);

s2.displayStack();

char ch = input.charAt(j);

System.out.println(``"当前解析的字符:"``+ch);

switch (ch) {

case '+'``:

case '-'``:

gotOper(ch,``1``);

break``;

case '*'``:

case '/'``:

gotOper(ch,``2``);

break``;

case '('``:

s1.push(ch);``//如果当前字符是'(',则将其入栈

break``;

case ')'``:

gotParen(ch);

break``;

default``:

//1、如果当前解析的字符是操作数,则直接压入s2

//2、

s2.push(ch);

break``;

}``//end switch

}``//end for

while``(!s1.isEmpty()){

s2.push(s1.pop());

}

return s2;

}

public void gotOper(``char opThis,``int prec1){

while``(!s1.isEmpty()){

char opTop = s1.pop();

if``(opTop == '('``){``//如果栈顶是'(',直接将操作符压入s1

s1.push(opTop);

break``;

}``else``{

int prec2;

if``(opTop == '+' || opTop == '-'``){

prec2 = 1``;

}``else``{

prec2 = 2``;

}

if``(prec2 < prec1){``//如果当前运算符比s1栈顶运算符优先级高,则将运算符压入s1

s1.push(opTop);

break``;

}``else``{``//如果当前运算符与栈顶运算符相同或者小于优先级别,那么将S1栈顶的运算符弹出并压入到S2中

//并且要再次再次转到while循环中与 s1 中新的栈顶运算符相比较;

s2.push(opTop);

}

}

}``//end while

//如果s1为空,则直接将当前解析的运算符压入s1

s1.push(opThis);

}

//当前字符是 ')' 时,如果栈顶是'(',则将这一对括号丢弃,否则依次弹出s1栈顶的字符,压入s2,直到遇到'('

public void gotParen(``char ch){

while``(!s1.isEmpty()){

char chx = s1.pop();

if``(chx == '('``){

break``;

}``else``{

s2.push(chx);

}

}

}

}

  三、测试

1

2

3

4

5

6

7

8

9

10

[@Test](https://my.oschina.net/azibug)

public void testInfixToSuffix(){

String input;

System.out.println(``"Enter infix:"``);

Scanner scanner = new Scanner(System.in);

input = scanner.nextLine();

InfixToSuffix in = new InfixToSuffix(input);

MyCharStack my = in.doTrans();

my.displayStack();

}

  四、结果

  Java数据结构和算法(六)——前缀、中缀、后缀表达式

   五、分析

  Java数据结构和算法(六)——前缀、中缀、后缀表达式

②、计算机如何实现后缀表达式的运算?

  Java数据结构和算法(六)——前缀、中缀、后缀表达式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

package com.ys.poland;

public class CalSuffix {

private MyIntStack stack;

private String input;

public CalSuffix(String input){

this``.input = input;

stack = new MyIntStack(input.length());

}

public int doCalc(){

int num1,num2,result;

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

char c = input.charAt(i);

if``(c >= '0' && c <= '9'``){

stack.push((``int``)(c-``'0'``));``//如果是数字,直接压入栈中

}``else``{

num2 = stack.pop();``//注意先出来的为第二个操作数

num1 = stack.pop();

switch (c) {

case '+'``:

result = num1+num2;

break``;

case '-'``:

result = num1-num2;

break``;

case '*'``:

result = num1*num2;

break``;

case '/'``:

result = num1/num2;

break``;

default``:

result = 0``;

break``;

}``//end switch

stack.push(result);

}``//end else

}``//end for

result = stack.pop();

return result;

}

public static void main(String[] args) {

//中缀表达式:1*(2+3)-5/(2+3) = 4

//后缀表达式:123+*123+/-

CalSuffix cs = new CalSuffix(``"123+*523+/-"``);

System.out.println(cs.doCalc()); //4

}

}

4、前缀表达式

  前缀表达式,指的是不包含括号,运算符放在两个运算对象的前面,严格从右向左进行(不再考虑运算符的优先规则),所有的计算按运算符出现的顺序。

  注意:后缀表达式是从左向右解析,而前缀表达式是从右向左解析。

①、如何将中缀表达式转换为前缀表达式?

  Java数据结构和算法(六)——前缀、中缀、后缀表达式

②、计算机如何实现前缀表达式的运算?

  Java数据结构和算法(六)——前缀、中缀、后缀表达式

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
thinkphp3.2.3模板渲染支持三元表达式
thinkphp3.2.3模板渲染支持三元表达式{$status?'正常':'错误'}{$info'status'?$info'msg':$info'error'}注意:三元运算符中暂时不支持点语法。如下:           <divclass"modalhidefade"id'myModa
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这