分析树

分析树

数学表达式作为分析树,例如 ((7 + 3)*(5-2))

树的层次结构有助于我们了解整个表达式的求值顺序。在我们计算顶层乘法之前,我们必须计算子树中的加法和减法。作为左子树的加法结果为10。减法,即右子树,计算结果为3。

构建分析树的第一步是将表达式字符串拆分成符号列表。 有四种不同的符号要考虑:左括号,右括号,运算符和操作数。

分析树构建规则

我们可以定义四个规则如下:

  • 如果当前符号是 '(',添加一个新节点作为当前节点的左子节点,并下降到左子节点。
  • 如果当前符号在列表 ['+',' - ','/','*'] 中,请将当前节点的根值设置为由当前符号表示的运算符。 添加一个新节点作为当前节点的右子节点,并下降到右子节点。
  • 如果当前符号是数字,请将当前节点的根值设置为该数字并返回到父节点。
  • 如果当前令牌是 ')',则转到当前节点的父节点。

例如表达式(3+(4 * 5)),把这个表达式解析成下面的字符标记列表 ['(','3','+','(','4','*','5',')',')'],分析树构建过程按照上面的规则可以分解为:


按照上述的方法,我们知道需要记住当前跟根节点的位置,以便返回,我们借助栈来实现,每次向下创建子节点的时候,将父节点入栈,每次返回到父节点的时候,我们从栈中弹出一个元素。

分析树实现

from stack import Stack
from binaryTree import *


def buildParseTree(fpexp):
    #分割字符串
    fplist = fpexp.split()
    #创建一个辅助栈
    pSack = Stack()
    #创建一个空的根节点并且标记好,以便最终返回
    eTree = BinaryTree('')
    #将当前的根节点入栈
    pSack.push(eTree)
    #创建一个根节点的标志
    currentTree = eTree

    for i in fplist:
        #如果当前是左括号,那么新增加一个左子节点,将当前节点移动到左子节点
        if i == '(':
            currentTree.insertLeft('')
            pSack.push(currentTree)
            currentTree = currentTree.getLeftChild()
        # 如果当前的项是数字,那么就将当前节点设置为这个数字,并且将当前节点移动到父节点
        elif i not in ['+','-','*','/',')']:
            currentTree.setRootVal(int(i)) #转换成整型
            parent = pSack.pop()
            currentTree = parent
        #如果当前的项是运算符,那么就将当前节点设置成这个运算符,并且新建一个右子节点,当前节点移动到这个新建的右子节点
        elif i in ['+','-','*','/']:
            currentTree.setRootVal(i)
            currentTree.insertRight('')
            pSack.push(currentTree)
            currentTree = currentTree.getRightChild()
        elif i == ')':
            currentTree = pSack.pop()
        else:
            raise ValueError
    return eTree

测试:

pt = buildParseTree("( 3 + ( 4 * 5 ) )")
print("前序遍历的结果:")
pt.preorder()
print("中序遍历的结果:")
pt.inorder()
print("后序遍历的结果:")
pt.postorder()

输出:

前序遍历的结果:
+
3
*
4
5
中序遍历的结果:
3
+
4
*
5
后序遍历的结果:
3
4
5
*
+

参考:

  1. 栈和二叉树实现代码
posted @ 2019-01-06 18:46  youngliu91  阅读(1092)  评论(0编辑  收藏  举报