python算法——字符串表达式的计算(转自:无限大地NLP_空木)

新博客地址: vonsdite.cn

 

原文戳这里!!!

 

preface:最近有个面试,被要求给出一个字符串表达式,计算出结果。本以为是见到过的,想着用一个栈,然后被面试官打断说你这样是有问题的,然后想了说用树,又被打断说是有问题的,再仔细想想。结果还是没整出来。哎。回来翻了下leetcode发现有两道类似。

  1. leetcode 224 Basic Calculator https://leetcode.com/problems/basic-calculator/有点类似,可这特么只用加减和括号不用乘除啊,妈的智障。这题用栈AC了。
  2. leetcode 227 Basic Calculator II https://leetcode.com/problems/basic-calculator-ii/也有点类似,只是差了括号。

但这两道还是不够。翻书加上与同仁的讨论,发现只需要将表达式化为二叉树的后缀表达式即可,有了后缀表达式,就比较简单了。后缀表达式是能够唯一确定表达式树的。后序遍历表达式树即可。用栈对后缀表达式进行处理也可以的。主要还是需要将字符串表达式化为后缀表达式。

另外,计算字符串表达式,Python有个内置函数eval(),直接使用eval("1+2*(3-1)-4")即可。

coding:

 

[python] view plain copy

  1. # -*- coding: utf-8 -*-  
  2. """ 
  3. Created on Sun Jul 10 15:39:28 2016 
  4.  
  5. @author: Administrator 
  6. """  
  7. operator_precedence = {  
  8.     '(' : 0,  
  9.     ')' : 0,  
  10.     '+' : 1,  
  11.     '-' : 1,  
  12.     '*' : 2,  
  13.     '/' : 2  
  14. }  
  15.   
  16. def postfix_convert(exp):  
  17.     ''''' 
  18.     将表达式字符串,转为后缀表达式 
  19.     如exp = "1+2*(3-1)-4" 
  20.     转换为:postfix = ['1', '2', '3', '1', '-', '*', '+', '4', '-'] 
  21.     '''  
  22.     stack = []          #运算符栈,存放运算符  
  23.     postfix = []        #后缀表达式栈  
  24.     for char in exp:  
  25. #        print char, stack, postfix  
  26.         if char not in operator_precedence:#非符号,直接进栈  
  27.             postfix.append(char)  
  28.         else:  
  29.             if len(stack) == 0:#若是运算符栈啥也没有,直接将运算符进栈  
  30.                 stack.append(char)  
  31.             else:  
  32.                 if char == "(":  
  33.                     stack.append(char)             
  34.                 elif char == ")":#遇到了右括号,运算符出栈到postfix中,并且将左括号出栈  
  35.                     while stack[-1]!="(":  
  36.                         postfix.append(stack.pop())  
  37.                     stack.pop()  
  38.                       
  39.                 elif operator_precedence[char] > operator_precedence[stack[-1]]:  
  40.                     #只要优先级数字大,那么就继续追加  
  41.                     stack.append(char)  
  42.                 else:  
  43.                     while len(stack)!=0:  
  44.                         if stack[-1]=="(":#运算符栈一直出栈,直到遇到了左括号或者长度为0  
  45.                             break  
  46.                         postfix.append(stack.pop())#将运算符栈的运算符,依次出栈放到表达式栈里面  
  47.                     stack.append(char)#并且将当前符号追放到符号栈里面  
  48.                       
  49.     while len(stack)!=0:#如果符号站里面还有元素,就直接将其出栈到表达式栈里面  
  50.         postfix.append(stack.pop())  
  51.     return postfix  
  52. #===========================这部分用于构造表达式树,不涉及计算================================#  
  53. class Node(object):  
  54.     def __init__(self, val):  
  55.         self.val = val  
  56.         self.left = None  
  57.         self.right = None  
  58. def create_expression_tree(postfix):  
  59.     """ 
  60.     利用后缀表达式,构造二叉树 
  61.     """  
  62.     stack = []  
  63.     #print postfix  
  64.     for char in postfix:  
  65.         if char not in operator_precedence:  
  66.             #非操作符,即叶子节点  
  67.             node = Node(char)     
  68.             stack.append(node)  
  69.         else:  
  70.             #遇到了运算符,出两个,进一个。  
  71.             node = Node(char)  
  72.             right = stack.pop()  
  73.             left = stack.pop()  
  74.             node.right = right  
  75.             node.left = left  
  76.             stack.append(node)  
  77.     #将最后一个出了即可。  
  78.     return stack.pop()  
  79. def inorder(tree):  
  80.     if tree:  
  81.         inorder(tree.left)  
  82.         print tree.val  
  83.         inorder(tree.right)  
  84. #=============================这部分用于计算值===================================#  
  85. def calculate(num1, op, num2):  
  86.     if not num1.isdigit() and not num2.isdigit():  
  87.         raise "num error"  
  88.     else:  
  89.         num1 = int(num1)  
  90.         num2 = int(num2)  
  91.     if op == "+":  
  92.         return num1 + num2  
  93.     elif op == "-":  
  94.         return num1 - num2  
  95.     elif op == "*":  
  96.         return num1 * num2  
  97.     elif op == "/":  
  98.         if num2==0:  
  99.             raise "zeros error"  
  100.         else:  
  101.             return num1/num2  
  102.     else:  
  103.         raise "op error"  
  104.       
  105. def cal_expression_tree(postfix):  
  106.     stack = []  
  107.     for char in postfix:  
  108.         stack.append(char)  
  109.         if char in "+-*/":  
  110.             op    = stack.pop()  
  111.             num2  = stack.pop()  
  112.             num1  = stack.pop()  
  113.             value = calculate(num1, op, num2)  
  114.             value = str(value)#计算结果是数值类型,将其化为字符串类型  
  115.             stack.append(value)  
  116.     return int(stack[0])  
  117. if __name__=="__main__":  
  118.     #另外异常情况的判断的话,可以使用try catch  
  119.     exp = "1+2*(3-1)-4"  
  120.     postfix = postfix_convert(exp)  
  121.       
  122.     #print "postfix:",postfix  
  123.     #tree    = create_expression_tree(postfix)  
  124.     #inorder(tree)  
  125.       
  126.     print cal_expression_tree(postfix)  

 

 

 

首先,运算符的优先级的定义operator_precedence字典的定义比较重要。遇到了(3-1*2)与(3*1-1)这两种情况,对三种运算符的优先级左右括号、减号、乘号,就不能简单的出栈进栈进行运算了。

其次,postfix_convert()函数将字符串表达式化为后缀表达式是关键。

最后,对于异常情况的处理,可以使用try catch,或者提前判断,这里在calculate()函数里面做了些判断。

主要参考:

 

  1. Expression tree
  2. 《数据结构与高分笔记》P132
  3. 顺序堆栈应用--表达式计算

 

转载请认证:无限大地nlp_空木的博客

你可能感兴趣的:(python算法——字符串表达式的计算(转自:无限大地NLP_空木))