前序、中序、后序表达式举例:
从这个表格中可以看到中序表达式和前序表达式、后序表达式的区别,中序表达式有括号,前序和后序没有括号。
那么为什么前序表达式和后序表达式不需要括号?答案是,这两种表达式中的运算符所对应的操作数是明确的。只有中序表达式需要额外的符号来消除歧义。前序表达式和后序表达式的运算顺序完全由运算符的位置决定。
以A + B * C为例,操作数 A 、B 和 C 的相对位置保持不变,只有运算符改变了位置。再观察中序表达式中的运算符。从左往右看,第一个出现的运算符是 + 。但是在后序表达式中,由于 * 的优先级更高(写成完全括号表达式后乘法所在的括号先进行运算),因此 * 先于 + 出现,前序表达式与后序表达式相反。
将中序表达式转换为后序表达式的步骤如下:
(1) 创建用于保存运算符的空栈,以及一个用于保存结果的空列表。
(2) 从左往右扫描这个标记列表。
- 如果标记是操作数,将其添加到结果列表的末尾。
- 如果标记是左括号,将其压入栈中。
- 如果标记是右括号,反复从栈中移除元素,直到移除对应的左括号。将从栈中
- 取出的每一个运算符都添加到结果列表的末尾。
- 如果标记是运算符,将其压入栈中。但是,在这之前,需要先从栈中取出优先
- 级更高或相同的运算符,并将它们添加到结果列表的末尾。
(3) 当处理完输入表达式以后,检查栈中是否有多余的运算符。将其中所有残留的运算符全部添加到结果列表的末尾。
以A*B+C*D为例,转换后表达式为AB*CD*+:
中序表达式转换后序表达式代码如下:
首先创建栈的结构
class Stack(object):
def __init__(self):
self.__items = []
def isEmpty(self):
"""检查栈是否为空"""
return self.__items == []
def push(self, item):
"""将一个元素添加到栈的顶端"""
self.__items.append(item)
def pop(self):
"""将栈顶端的元素移除"""
return self.__items.pop()
def peek(self):
"""返回栈顶端的元素"""
return self.__items[len(self.__items) - 1]
def size(self):
"""返回栈中元素的数目"""
return len(self.__items)
转换表达式
import stack
import string
def toPostfix(symbolString):
"""中序表达式转后序表达式"""
# 设定操作符优先级,保证乘除优先级大于加减大于括号即可
# 不需要设‘)’的优先级,因为不会使用到
prec = {}
prec['/'] = 3
prec['*'] = 3
prec['+'] = 2
prec['-'] = 2
prec['('] = 1
s = stack.Stack()
str_list = []
for token in symbolString:
if token in string.ascii_uppercase:
str_list.append(token)
elif token == '(':
s.push(token)
elif token == ')': # 找到前一个“(”匹配
peek = s.pop()
# 如果是操作符就直接把操作符移入列表中
while peek != '(':
str_list.append(peek)
peek = s.pop()
else:
# 保证进入列表的优先级比栈中操作符的优先级要低
while (not s.isEmpty()) and prec[token] <= prec[s.peek()]:
str_list.append(peek)
s.push(token)
# 将剩余的栈中的操作符加入到列表中
while not s.isEmpty():
str_list.append(s.pop())
return ''.join(str_list)
中序转前序表达式原理同后序是一样的,只不过在后序的基础上进行了字符串的反转
中序表达式转前序表达式步骤如下:
(1)反转输入字符串,如“(A+B)*(C+D)” 反转后为“(D+C)*(B+A)”。
(2)从字符串中取出下一个字符。
- 如果是操作数,则直接输出。
- 如果是“)”,压入栈中。
- 如果是运算符但不是“(”,“)”,则不断循环进行以下处理:如果栈为空,则此运算符进栈,结束此步骤;如果栈顶是“)”,则此运算符进栈,结束此步骤;如果此运算符与栈顶优先级相同或者更高,此运算符进栈,结束此步骤;否则,运算符连续出栈,直到满足上述三个条件之一,然后此运算符进栈。
- 如果是“(”,则运算符连续出栈,直到遇见“)”为止,将“)”出栈且丢弃之。
- 如果还有更多的字符串,则转到第2步。
- 如果不再有未处理的字符串了,输出栈中剩余元素。
(3)再次反转字符串得到最终结果。
中序表达式转换前序表达式代码如下:
def toPrefix(symbolString):
"""中序表达式转前序表达式"""
prec = {}
prec['/'] = 3
prec['*'] = 3
prec['+'] = 2
prec['-'] = 2
prec[')'] = 1
s = stack.Stack()
str_list = []
symbolString = symbolString[::-1] # 反转表达式
for token in symbolString:
if token in string.ascii_uppercase:
str_list.append(token)
elif token == ')':
s.push(token)
elif token == '(': # 找到前一个“)”匹配
peek = s.pop()
# 如果是操作符就直接把操作符移入列表中
while peek != ')':
str_list.append(peek)
peek = s.pop()
else:
# 保证进入列表的优先级比栈中操作符的优先级要低
while (not s.isEmpty()) and prec[token] < prec[s.peek()]:
str_list.append(s.pop())
s.push(token)
# 将剩余的栈中的操作符加入到列表中
while not s.isEmpty():
str_list.append(s.pop())
return ''.join(str_list[::-1])