1. 程式人生 > >python演算法——字串表示式的計算(轉自:無限大地NLP_空木)

python演算法——字串表示式的計算(轉自:無限大地NLP_空木)

preface:最近有個面試,被要求給出一個字串表示式,計算出結果。本以為是見到過的,想著用一個棧,然後被面試官打斷說你這樣是有問題的,然後想了說用樹,又被打斷說是有問題的,再仔細想想。結果還是沒整出來。哎。回來翻了下leetcode發現有兩道類似。

但這兩道還是不夠。翻書加上與同仁的討論,發現只需要將表示式化為二叉樹的字尾表示式即可,有了字尾表示式,就比較簡單了。字尾表示式是能夠唯一確定表示式樹的。後序遍歷表示式樹即可。用棧對字尾表示式進行處理也可以的。主要還是需要將字串表示式化為字尾表示式。

另外,計算字串表示式,Python有個內建函式eval(),直接使用eval("1+2*(3-1)-4")即可。

coding:

  1. # -*- coding: utf-8 -*-
  2. """ 
  3. Created on Sun Jul 10 15:39:28 2016 
  4. @author: Administrator 
  5. """
  6. operator_precedence = {  
  7.     '(' : 0,  
  8.     ')' : 0,  
  9.     '+' : 1,  
  10.     '-' : 1,  
  11.     '*' : 2,  
  12.     '/' : 2
  13. }  
  14. def postfix_convert(exp):  
  15.     ''''' 
  16.     將表示式字串,轉為字尾表示式 
  17.     如exp = "1+2*(3-1)-4"
     
  18.     轉換為:postfix = ['1', '2', '3', '1', '-', '*', '+', '4', '-'] 
  19.     '''
  20.     stack = []          #運算子棧,存放運算子
  21.     postfix = []        #字尾表示式棧
  22.     for char in exp:  
  23. #        print char, stack, postfix
  24.         if char notin operator_precedence:#非符號,直接進棧
  25.             postfix.append(char)  
  26.         else
    :  
  27.             if len(stack) == 0:#若是運算子棧啥也沒有,直接將運算子進棧
  28.                 stack.append(char)  
  29.             else:  
  30.                 if char == "(":  
  31.                     stack.append(char)             
  32.                 elif char == ")":#遇到了右括號,運算子出棧到postfix中,並且將左括號出棧
  33.                     while stack[-1]!="(":  
  34.                         postfix.append(stack.pop())  
  35.                     stack.pop()  
  36.                 elif operator_precedence[char] > operator_precedence[stack[-1]]:  
  37.                     #只要優先順序數字大,那麼就繼續追加
  38.                     stack.append(char)  
  39.                 else:  
  40.                     while len(stack)!=0:  
  41.                         if stack[-1]=="(":#運算子棧一直出棧,直到遇到了左括號或者長度為0
  42.                             break
  43.                         postfix.append(stack.pop())#將運算子棧的運算子,依次出棧放到表示式棧裡面
  44.                     stack.append(char)#並且將當前符號追放到符號棧裡面
  45.     while len(stack)!=0:#如果符號站裡面還有元素,就直接將其出棧到表示式棧裡面
  46.         postfix.append(stack.pop())  
  47.     return postfix  
  48. #===========================這部分用於構造表示式樹,不涉及計算================================#
  49. class Node(object):  
  50.     def __init__(self, val):  
  51.         self.val = val  
  52.         self.left = None
  53.         self.right = None
  54. def create_expression_tree(postfix):  
  55.     """ 
  56.     利用字尾表示式,構造二叉樹 
  57.     """
  58.     stack = []  
  59.     #print postfix
  60.     for char in postfix:  
  61.         if char notin operator_precedence:  
  62.             #非操作符,即葉子節點
  63.             node = Node(char)     
  64.             stack.append(node)  
  65.         else:  
  66.             #遇到了運算子,出兩個,進一個。
  67.             node = Node(char)  
  68.             right = stack.pop()  
  69.             left = stack.pop()  
  70.             node.right = right  
  71.             node.left = left  
  72.             stack.append(node)  
  73.     #將最後一個出了即可。
  74.     return stack.pop()  
  75. def inorder(tree):  
  76.     if tree:  
  77.         inorder(tree.left)  
  78.         print tree.val  
  79.         inorder(tree.right)  
  80. #=============================這部分用於計算值===================================#
  81. def calculate(num1, op, num2):  
  82.     ifnot num1.isdigit() andnot num2.isdigit():  
  83.         raise"num error"
  84.     else:  
  85.         num1 = int(num1)  
  86.         num2 = int(num2)  
  87.     if op == "+":  
  88.         return num1 + num2  
  89.     elif op == "-":  
  90.         return num1 - num2  
  91.     elif op == "*":  
  92.         return num1 * num2  
  93.     elif op == "/":  
  94.         if num2==0:  
  95.             raise"zeros error"
  96.         else:  
  97.             return num1/num2  
  98.     else:  
  99.         raise"op error"
  100. def cal_expression_tree(postfix):  
  101.     stack = []  
  102.     for char in postfix:  
  103.         stack.append(char)  
  104.         if char in"+-*/":  
  105.             op    = stack.pop()  
  106.             num2  = stack.pop()  
  107.             num1  = stack.pop()  
  108.             value = calculate(num1, op, num2)  
  109.             value = str(value)#計算結果是數值型別,將其化為字串型別
  110.             stack.append(value)  
  111.     return int(stack[0])  
  112. if __name__=="__main__":  
  113.     #另外異常情況的判斷的話,可以使用try catch
  114.     exp = "1+2*(3-1)-4"
  115.     postfix = postfix_convert(exp)  
  116.     #print "postfix:",postfix
  117.     #tree    = create_expression_tree(postfix)
  118.     #inorder(tree)
  119.     print cal_expression_tree(postfix)  

首先,運算子的優先順序的定義operator_precedence字典的定義比較重要。遇到了(3-1*2)與(3*1-1)這兩種情況,對三種運算子的優先順序左右括號、減號、乘號,就不能簡單的出棧進棧進行運算了。

其次,postfix_convert()函式將字串表示式化為字尾表示式是關鍵。

最後,對於異常情況的處理,可以使用try catch,或者提前判斷,這裡在calculate()函式裡面做了些判斷。

主要參考: