浅析前缀,后缀,中缀表达式转化求值问题

开发 前端
上次介绍如何利用栈实现中缀表达式求值,如果我是出题官,当然要考前缀,后缀,中缀表达式相互转换,然后就变成了利用栈实现前缀和后缀表达式求值。

[[358891]]

 算法,一门既不容易入门,也不容易精通的学问。

上次介绍如何利用栈实现中缀表达式求值,如果我是出题官,当然要考前缀,后缀,中缀表达式相互转换,然后就变成了利用栈实现前缀和后缀表达式求值。

前缀,后缀,中缀表达式相互转换及其运算,可以说是计算机考研的一个重点。

首先看下面所示表格:

  • 注意:前序表达式和后序表达式是没有扩号

这篇文章有对应的图解:https://mp.weixin.qq.com/s/NRbFXZAXEUeXhKKYY7CReg

中缀表达式转前缀表达式求值

中缀表达式转前缀表达式的规则:

  1. 1、反转输入字符串,如“2*3/(2-1)+3*(4-1)” 反转后为“ )1-4(*3+)1-2(/3*2”, 
  2. 2、从字符串中取出下一个字符 
  3.   2.1.如果是操作数,直接输出 
  4.   2.2.如果是“)”,压入栈中 
  5.   2.3.如果是运算符但不是“(”,“)”,则不断循环进行以下处理 
  6.     2.3.1.如果栈为空,则此运算符进栈,结束此步骤 
  7.     2.3.2.如果栈顶是“)”,则此运算符进栈,结束此步骤 
  8.     2.3.2.如果此运算符与栈顶优先级相同或者更高,此运算符进栈,结束此步骤 
  9.     2.3.4.否则,运算符连续出栈,直到满足上述三个条件之一,然后此运算符进栈 
  10.   2.4、如果是“(”,则运算符连续出栈,直到遇见“)”为止,将“)”出栈且丢弃之 
  11. 3、如果还有更多的字符串,则转到第2步 
  12. 4、不在有未处理的字符串了,输出栈中剩余元素 
  13. 5、再次反转字符串得到最终结果 

经过上面的步骤,得到的输出既是转换得到的前缀表达式。

前缀表达式的计算方法:对前缀表达式从后向前扫描,设定一个操作数栈,如果是操作数,则将其直接入栈,如果是操作符,则从栈中弹出操作符对应的操作数进行运算,并将计算结果压栈。直至从右到左扫描完毕整个前缀表达式,这时操作数栈中应该只有一个元素,该元素的值则为前缀表达式的计算结果。

上面的过程使用数据结构栈来实现,具体代码如下

  1. ''
  2. @Author:Runsen 
  3. @WeChat:RunsenLiu  
  4. @微信公众号:Python之王 
  5. @CSDN:https://blog.csdn.net/weixin_44510615 
  6. @Github:https://github.com/MaoliRUNsen 
  7. @Date:2020/12/17 
  8. ''
  9. import re 
  10.  
  11. class Stack(): 
  12.     def __init__(self): 
  13.         self.items = [] 
  14.  
  15.     def push(self, item): 
  16.         return self.items.append(item) 
  17.  
  18.     def pop(self): 
  19.         return self.items.pop() 
  20.  
  21.     def size(self): 
  22.         return len(self.items) 
  23.  
  24.     def peek(self): 
  25.         return self.items[len(self.items) - 1] 
  26.  
  27.     def display(self): 
  28.         print(self.items) 
  29.  
  30. def infix_to_prefix(s): 
  31.     prec = { 
  32.         '*': 3, 
  33.         '/': 3, 
  34.         '+': 2, 
  35.         '-': 2, 
  36.         '(': 4, 
  37.         ')': 1 
  38.     } 
  39.  
  40.     a = re.findall('[1-9]\d*|[\+\-\*\/\(\)]', input('请输入中缀表达式:')) 
  41.     prefix = [] 
  42.  
  43.     for x in a[::-1]: 
  44.         if re.match('[0-9]', x): 
  45.             #操作数,直接输出 
  46.             prefix.append(x) 
  47.         else
  48.             #如果是“)”,压入栈中 
  49.             if x == ')'
  50.                 s.push(x) 
  51.             elif x == '('
  52.                 while True
  53.                     i = s.pop() 
  54.                     if i == ')'
  55.                         break 
  56.                     else
  57.                         prefix.append(i) 
  58.             else
  59.                 if s.size() > 0 and prec[x] <= prec[s.peek()]: 
  60.                     prefix.append(s.pop()) 
  61.                 s.push(x) 
  62.     for _ in range(s.size()): 
  63.         prefix.append(s.pop()) 
  64.     return prefix[::-1] 
  65.      
  66. def cal_prefix(s, prefix): 
  67.     # 思路:对前缀表达式从后向前扫描,设定一个操作数栈,如果是操作数,则将其直接入栈,如果是操作符,则从栈中弹出操作符对应的操作数进行运算,并将计算结果压栈。 
  68.     # 直至从右到左扫描完毕整个前缀表达式,这时操作数栈中应该只有一个元素,该元素的值则为前缀表达式的计算结果。 
  69.     for x in prefix[::-1]: 
  70.         if re.match('[0-9]', x): 
  71.             s.push(x) 
  72.         else
  73.             a2 = int(s.pop()) 
  74.             a1 = int(s.pop()) 
  75.             if x == '*'
  76.                 a = a1 * a2 
  77.             elif x == '/'
  78.                 a = a2 / a1 
  79.             elif x == '+'
  80.                 a = a1 + a2 
  81.             else
  82.                 a = a2 - a1 
  83.             s.push(a) 
  84.     return s.pop() 
  85.  
  86. if __name__ == '__main__'
  87.     s = Stack() 
  88.     prefix = infix_to_prefix(s) 
  89.     print('前缀表达式:', prefix) 
  90.     prefix_val = cal_prefix(s, prefix) 
  91.     print('前缀表达式计算结果:', prefix_val) 
  92.  
  93. 请输入中缀表达式:2*3/(2-1)+3*(4-1) 
  94. 前缀表达式: ['+''*''2''/''3''-''2''1''*''3''-''4''1'
  95. 前缀表达式计算结果: 15 
  96. 请输入中缀表达式:9+(3-1*2)*3+10/2 
  97. 前缀表达式: ['+''+''9''*''-''3''*''1''2''3''/''10''2'
  98. 前缀表达式计算结果: 17 

中缀表达式转换为后缀表达式求值

中缀表达式转后缀表达式的规则:

1.遇到操作数,直接输出;

2.栈为空时,遇到运算符,入栈;

3.遇到左括号,将其入栈;

4.遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出;

5.遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;

6.最终将栈中的元素依次出栈,输出。

经过上面的步骤,得到的输出既是转换得到的后缀表达式。

后缀表达式的计算方法:对后缀表达式从前向后扫描,设定一个操作数栈,如果是操作数,则将其直接入栈,如果是操作符,则从栈中弹出操作符对应的操作数进行运算,并将计算结果压栈。直至从右到左扫描完毕整个后缀表达式,这时操作数栈中应该只有一个元素,该元素的值则为后缀表达式的计算结果。

上面的过程使用数据结构栈来实现,具体代码如下:

  1. ''
  2. @Author:Runsen 
  3. @WeChat:RunsenLiu 
  4. @微信公众号:Python之王 
  5. @CSDN:https://blog.csdn.net/weixin_44510615 
  6. @Github:https://github.com/MaoliRUNsen 
  7. @Date:2020/12/17 
  8. ''
  9. import re 
  10.  
  11. class Stack(): 
  12.     def __init__(self): 
  13.         self.items = [] 
  14.  
  15.     def push(self, item): 
  16.         return self.items.append(item) 
  17.  
  18.     def pop(self): 
  19.         return self.items.pop() 
  20.  
  21.     def size(self): 
  22.         return len(self.items) 
  23.  
  24.     def peek(self): 
  25.         return self.items[len(self.items) - 1] 
  26.  
  27.     def display(self): 
  28.         print(self.items) 
  29.  
  30.  
  31. def infix_to_postfix (s): 
  32.     prec = { 
  33.         '*': 3, 
  34.         '/': 3, 
  35.         '+': 2, 
  36.         '-': 2, 
  37.         '(': 1, 
  38.         ')': 4 
  39.     } 
  40.  
  41.     a = re.findall('[1-9]\d*|[\+\-\*\/\(\)]', input('请输入中缀表达式:')) 
  42.     postfix = [] 
  43.  
  44.     for x in a: 
  45.         if re.match('[0-9]', x): 
  46.             # 操作数,直接输出 
  47.             postfix.append(x) 
  48.         else
  49.             # 如果是“(”,压入栈中 
  50.             if x == '('
  51.                 s.push(x) 
  52.             elif x == ')'
  53.                 while True
  54.                     i = s.pop() 
  55.                     if i == '('
  56.                         break 
  57.                     else
  58.                         postfix.append(i) 
  59.             else
  60.                 if s.size() > 0 and prec[x] <= prec[s.peek()]: 
  61.                     postfix.append(s.pop()) 
  62.                 s.push(x) 
  63.     for _ in range(s.size()): 
  64.         postfix.append(s.pop()) 
  65.     return postfix 
  66.  
  67.  
  68. def cal_postfix (s, postfix): 
  69.     for x in postfix: 
  70.         if re.match('[0-9]', x): 
  71.             s.push(x) 
  72.         else
  73.             a1 = int(s.pop()) 
  74.             a2 = int(s.pop()) 
  75.             if x == '*'
  76.                 a = a1 * a2 
  77.             elif x == '/'
  78.                 a = a2 / a1 
  79.             elif x == '+'
  80.                 a = a1 + a2 
  81.             else
  82.                 a = a2 - a1 
  83.             s.push(a) 
  84.     return s.pop() 
  85.  
  86.  
  87. if __name__ == '__main__'
  88.     s = Stack() 
  89.     postfix = infix_to_postfix(s) 
  90.     print('后缀表达式:', postfix) 
  91.     postfix_val = cal_postfix (s, postfix) 
  92.     print('后缀表达式计算结果:', postfix_val) 
  93.  
  94.  
  95. 请输入中缀表达式:2*3/(2-1)+3*(4-1) 
  96. ['2''3''*''2''1''-''/''3''4''1''-'
  97. 后缀表达式: ['2''3''*''2''1''-''/''3''4''1''-''*''+'
  98. 后缀表达式计算结果: 15 
  99. 请输入中缀表达式:9+(3-1*2)*3+10/2 
  100. 后缀表达式: ['9''3''1''2''*''-''3''*''10''2''/''+''+'
  101. 后缀表达式计算结果: 17 

其实此题是Leetcode第150题,逆波兰表达式求值。

根据 逆波兰表示法,求表达式的值。

有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

  1. 示例 1: 
  2.  
  3. 输入: ["2""1""+""3""*"
  4. 输出: 9 
  5. 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9 
  6. 示例 2: 
  7.  
  8. 输入: ["4""13""5""/""+"
  9. 输出: 6 
  10. 解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6 

前缀表达式转中缀表达式

从右往左开始,取出一个操作符和操作符右边的两个数进行计算,并将计算的结果放过去,直到计算结束。以前缀表达式+/*23-21*3-41为例,将其转换为中缀表达式:

(1)取出-、4、1,计算并将结果放回得到+/*23-21*3(4-1);

(2)取出*、3、(4-1),计算并将结果放回得到+/*23-21(3*(4-1));

(3)取出-、2、1,计算并将结果放回得到+/*23(2-1)(3*(4-1));

(3)取出*、2、3,计算并将结果放回得到+/(2*3)(2-1)(3*(4-1));

(4)取出/、(2*3)、(2-1),计算并将结果放回得到+((2*3)/(2-1))(3*(4-1));

(5)取出+、((2*3)/(2-1))、(3*(4-1)),计算将结果放回得到((2*3)/(2-1))+(3*(4-1)),计算结束,显然计算结果为15。

后缀表达式转中缀表达式从左向右开始,取出一个操作符和操作符左边的两个数进行计算,并将计算的结果放过去,直到计算结束,以后缀表达式23*21-/341-*+为例,将其转换为中缀表达式:(1)取出2、3、*,计算并将结果放回得到(2*3)21-/341-*+;

(2)取出2,1,-,计算并将结果放回得到(2*3)(2-1)/341-*+;

(3)取出(2*3)、(2-1)、/,计算并将结果放回得到((2*3)/(2-1))341-*+;

(4)取出4,1,-,计算并将结果放回得到((2*3)/(2-1)) 3(4-1)*+;

(5)取出3,(4-1),*,计算并将结果放回得到((2*3)/(2-1)) 3*(4-1)+;

(6)取出((2*3)/(2-1)),3*(4-1),+,计算并将结果放回得到((2*3)/(2-1)) + 3*(4-1),显然计算结果为15。

本文已收录 GitHub: https://github.com/MaoliRUNsen/runsenlearnpy100

 

责任编辑:姜华 来源: Python之王
相关推荐

2009-09-09 17:45:07

Linq表达式

2023-12-13 10:12:40

Python函数lambda

2009-09-16 17:15:57

正则表达式引擎

2019-04-16 13:30:05

表达式求值数据结构算法

2009-09-17 09:09:50

Lambda表达式Linq查询

2009-08-07 15:16:10

C#正则表达式

2010-07-19 10:40:16

Perl正则表达式

2009-09-16 15:45:56

email的正则表达式

2009-08-11 16:03:13

C#运算符

2009-09-16 11:17:12

PHP正则表达式定位字

2021-03-14 08:27:40

Java数据结构算法

2022-11-24 06:33:43

表达式求值运算

2009-09-16 13:24:30

PHP正则表达式匹配

2009-09-16 16:01:57

PHP正则表达式正则表达式的应用

2010-10-08 09:17:07

JavaScript表JavaScript运

2009-09-16 10:43:22

PHP正则表达式函数

2009-09-16 18:03:05

Java正则表达式正则表达式实现

2009-08-20 14:43:03

C#正则表达式Rege

2009-08-20 13:09:28

C#正则表达式

2020-12-18 09:05:13

算法单调栈
点赞
收藏

51CTO技术栈公众号