1. 程式人生 > >15_資料結構與演算法_分析樹_Python實現

15_資料結構與演算法_分析樹_Python實現

#Created By: Chen Da

#這裡針對簡單的數學表示式使用分析樹
"""
(3+(4*5))

定義四個規則:
    1、如果當前符號是'(',新增一個新節點作為當前節點的左子節點,並下降到左子節點;
    2、如果當前符號在列表['+','-','/','*']中,將當前節點的根植設定為由當前符號表示的運算子,新增一個新節點作為當前節點的右子節點,
       並下降到右子節點;
    3、如果當前符號是數字,請將當前節點的根植設定為該數字並返回父節點;
    4、如果當前令牌是')',則轉到當前節點的父節點。
"""

#先建立一個stack類
class Stack(object):
    def __init__(self):
        self.items = []

    def is_empty(self):
        return len(self.items) == 0

    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)

#建立一個二叉樹類
class BinaryTree(object):
    def __init__(self,root_obj):
        self.key = root_obj
        self.left_child = None
        self.right_child = None

    def insert_left(self,new_node):
        if self.left_child is None:
            self.left_child = BinaryTree(new_node)
        else:
            tree_ = BinaryTree(new_node)
            tree_.left_child = self.left_child
            self.left_child = tree_

    def insert_right(self,new_node):
        if self.right_child is None:
            self.right_child = BinaryTree(new_node)
        else:
            tree_ = BinaryTree(new_node)
            tree_.right_child = self.right_child
            self.right_child = tree_

    def get_left_child(self):
        return self.left_child

    def get_right_child(self):
        return self.right_child

    def get_root_val(self):
        return self.root_obj

    def set_root_val(self,obj):
        self.key = obj

#建立一個分析樹
def build_parse_tree(fpexp):
    fp_list = fpexp.split()
    p_stack = Stack()
    e_tree = BinaryTree('')         #建立一個空樹
    p_stack.push(e_tree)
    current_tree = e_tree
    for i in fp_list:
        if i == '(':
            current_tree.insert_left(i)         #建立一個新節點作為根的左子節點
            p_stack.push(current_tree)
            current_tree = current_tree.get_left_child()    #使當前節點到該新子節點
        elif i not in ['+','-','/','*']:
            current_tree.set_root_val(int(i))   #將當前根值設定為該整數
            parent = p_stack.pop()
            current_tree = parent       #使當前節點返回到父節點
        elif i in ['+','-','/','*']:
            current_tree.set_root_val(i)    #將當前根節點的根值設定為運算子號
            current_tree.insert_right('')   #新增一個新節點作為右子節點
            p_stack.push(current_tree)
            current_tree = current_tree.get_right_child()   #當前節點指向新的右子節點
        elif i == ')':
            current_tree = p_stack.pop()    #當前節點返回父節點
        else:
            raise ValueError
    return e_tree

#寫一個評估分析樹的函式,簡單的返回對應葉節點的值
def test_parse_tree(parse_tree):
    import operator
    opers = {
            '+':operator.add,'-':operator.sub,
            '*':operator.mul,'/':operator.truediv
            }
    #獲取當前節點左右子節點的引用
    left_child = parse_tree.get_left_child()
    right_child = parse_tree.get_right_child()
    #判斷如果左右子樹都是None,當前節點是一個葉節點
    #如果當前節點不是葉節點,將當前節點的運算子應用於遞迴計算左右子節點的運算中
    if left_child and right_child:
        fn = opers(parse_tree.get_root_val())
        return fn(test_parse_tree(left_child),test_parse_tree(right_child))
    else:
        return parse_tree.get_root_val()