基于Python的逆波兰表达式的转换与求值

一、逆波兰表达式简介

逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后)。而与之对应的是我们在数学中常见的 中缀表达式(既操作符在操作数中间)例如 12+23 就是典型的中缀式,而与之对应的逆波兰式则为12,13,+

二、用途

将传统的中缀式转化为后缀式后,可以简化计算机的计算。将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。方便计算机编程实现,例如(a+b) * (c+d)转换为ab+cd+*,就避免了括号的运算,在编程和计算上就较少了逻辑判断与分支的处理。

三、算法

(一). 逆波兰式的转换

首先创建两个空栈(Python中可用List实现栈的功能),stack_expr, stack_opr 分别来装操作数与操作符。从头开始遍历准备好的中缀式,按以下步骤进行转换: (注:此处本人将中缀式处理为List形式,以方便后续计算,读者可自行决定中缀式形式 )

附上本人处理后中缀式形式 : 2.0*(3.1+4.8)+5.0  ----> [2.0, '*', '(', 3.1, '+', 4.8, ')', '+', 5.0]

0、当前遍历到的字符记作Index
1、若index是数字, 将该index入栈stack_expr
2、若index是非数字:
	2.1、是左括号, 将左括号入栈stack_opr
	2.2、是右括号,将stack_opr中的操作符从栈顶依次出栈并入栈stack_expr, 直到遇到左括号终止操作(注意: 该左括号出栈stack_opr但不入栈stack_expr)这样就消除表达式中的括号消除了
	2.3、若index是普通操作符(+ - * /)
		 2.3.1、 若stack_opr为空, 操作符入栈stack_opr
		 2.3.2、 如果stack_opr不空,将stack_opr栈顶操作符与index比较优先级:
				2.3.2.1、若index的优先级高于stack_opr栈顶操作符的优先级,则index入栈  stack_opr
				2.3.2.2、若index的优先级小于或者等于stack_opr栈顶操作符, stack_opr栈顶操作符出栈并入栈  stack_expr,直到index优先级高于stack_opr 的优先级,将index入stack_opr栈。(注:若stack_opr出栈时,将stack_opr出空后,index直接入栈即可)
				
3、中缀式遍历结束后如果stack_opr栈不为空,则依次将操作符出栈并入栈stack_expr

代码实现:

	pat = ['+','-','*','/','(',')','%']
	def reverse_polish(data):
		stack_opr = list()
		#数字栈
		stack_expr = list()
		#优先级
		dicts = {
			'+' : 1,
			'-' : 1,
			'*' : 2,
			'/' : 2,
			'(' : 0
		}
	
		global pat
		
		for index in data:
			#1.数字,进expr栈
			if index not in pat:
				stack_expr.append(index)
			
			#2.非数字
			else:
				#2.1 opr栈空
				if	not stack_opr:
					stack_opr.append(index)
				#2.2 opr栈非空
				else:
					#2.2.1 index 是 左括号 ,入栈opr
					if index == '(':
						stack_opr.append(index)
					#2.2.2 index 是右括号,将栈顶的操作符出opr栈,并入expr栈 ,直到遇到左括号
					elif index ==')':
						while True:
							newdex = stack_opr.pop()
							#2.2.2.1 newdex是操作符
							if newdex != '(':
								stack_expr.append(newdex)
							#2.2.2.2 newdex 是左括号
							else:
								break
					#2.2.3 index是普通操作符
					else:
						while True:
							#2.2.3.0 opr栈空,则直接入栈
							if not stack_opr:
								stack_opr.append(index)
								break
							level_index = dicts[index]
							level_opr = dicts[stack_opr[-1]]
							#2.2.3.1 index 优先级 比 opr 栈顶优先级 高 ,index 入 opr栈
							if level_index > level_opr:
								stack_opr.append(index)
								break
							#2.2.3.2 index 优先级 比 opr 栈顶优先级 低或等于 , opr栈顶 出栈 并 入expr 栈,直到 index 优先级 高于 opr 栈顶优先级
							else:
								topdex = stack_opr.pop()
								stack_expr.append(topdex)
		#3. data 原表达式 已被遍历完,若opr 栈不为空,则依次出栈 进 expr栈
		while True:
			if len(stack_opr)!=0:
				dex = stack_opr.pop()
				stack_expr.append(dex)
			else:
				break
		return stack_expr

(二). 逆波兰式的计算
相对于将中缀式转换为逆波兰式,逆波兰式的计算就简单多了只需如下几步即可:

建立一个一个数值栈stack_res(同样用List实现),用于存放中间数值以及计算结果

遍历转换好的逆波兰式:

1、如果遇到数字,入栈stack_res;
2、如果遇到运算符, 从stack_res中依次出栈两个数与 遇到的操作符进行计算即可,将结果压入stack_res栈中 
3、 继续遍历下一个元素,直到结束;

代码实现

def compute(data):

	stack_res = list()
	
	global pat
	
	for index in data:
		#1 数字,进res栈
		if index not in  pat:
			stack_res.append(index)
		#2 运算符
		else:
			# 2.1 左右操作数
			right_ops = stack_res.pop()
			left_ops = stack_res.pop()
			
			if index == '*':
				res = left_ops*right_ops
				stack_res.append(res)
				
			 #出数不能为零,需要抛异常进行处理	
			if index == '/':
				res = left_ops/right_ops
				if right_ops == 0:
					raise Exception('Zero')
				stack_res.append(res)
				
			if index == '+':
				res = left_ops+right_ops
				stack_res.append(res)
				
			if index == '-':
				res = left_ops-right_ops
				stack_res.append(res)
				
	if len(stack_res) == 1:
		return stack_res[0]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值