【数据结构与算法Python版学习笔记】树——二叉树的应用:解析树
解析树(语法树)
- 将树用于表示语言中句子, 可以分析句子的各种语法成分, 对句子的各种成分进行处理
- 语法分析树
- 程序设计语言的编译
- 词法、语法检查
- 从语法树生成目标代码
- 自然语言处理
- 机器翻译
- 语义理解
表达式解析
\(((7+3)*(5-2))\)
- 叶节点保存操作数,内部节点保存操作符
- 树中每个子树都表示一个子表达式

构建解析树
定义规则
- 如果当前标记是(,就为当前节点添加一个左子节点,并下沉至该子节点;
- 如果当前标记在列表['+', '-', '/', '*']中,就将当前节点的值设为当前标记对应的运算符;为当前节点添加一个右子节点,并下沉至该子节点;
- 如果当前标记是数字,就将当前节点的值设为这个数并返回至父节点;
- 如果当前标记是),就跳到当前节点的父节点。
步骤

- 创建一棵空树。
- 读入第一个标记(。根据规则1,为根节点添加一个左子节点。
- 读入下一个标记3。根据规则3,将当前节点的值设为3,并回到父节点。
- 读入下一个标记+。根据规则2,将当前节点的值设为+,并添加一个右子节点。新节点成为当前节点。
- 读入下一个标记(。根据规则1,为当前节点添加一个左子节点,并将其作为当前节点。
- 读入下一个标记4。根据规则3,将当前节点的值设为4,并回到父节点。
- 读入下一个标记*。根据规则2,将当前节点的值设为*,并添加一个右子节点。新节点成为当前节点。
- 读入下一个标记5。根据规则3,将当前节点的值设为5,并回到父节点。
- 读入下一个标记)。根据规则4,将*的父节点作为当前节点。
- 读入下一个标记)。根据规则4,将+的父节点作为当前节点。因为+没有父节点,所以工作完成。
思路
- 创建左右子树可调用insertLeft/Right
- 当前节点设置值,可以调用setRootVal
- 下降到左右子树可调用getLeft/RightChild
- 上升到父节点,这个没有方法支持,用一个栈来记录跟踪父节点
- 当前节点下降时,将下降前的节点push入栈
- 当前节点需要上升到父节点时,上升到pop出栈的节点即可!
代码
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item): # 将item加入栈顶,无返回值
return 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:
def __init__(self, rootObj):
self.key = rootObj
self.leftChild = None
self.rightChild = None
def insertLeft(self, newNode):
if self.leftChild == None:
self.leftChild = BinaryTree(newNode)
else:
t = BinaryTree(newNode)
t.leftChild = self.leftChild
self.leftChild = t
def insertRignt(self, newNode):
if self.rightChild == None:
self.rightChild = BinaryTree(newNode)
else:
t = BinaryTree(newNode)
t.rightChild = self.rightChild
self.rightChild = t
def getRightChild(self):
return self.rightChild
def getLeftChild(self):
return self.leftChild
def setRootVal(self, obj):
self.key = obj
def getRootVal(self):
return self.key
def buildParseTree(fpexp):
fplist = fpexp.split()
pstack = Stack()
eTree = BinaryTree('')
# 入栈下降
pstack.push(eTree)
currentTree = eTree
for i in fplist:
# 表达式开始
if i == '(':
currentTree.insertLeft('')
pstack.push(currentTree) # 入栈下降
currentTree = currentTree.getLeftChild
elif i not in ['+', '-', '*', '/', ')']:
currentTree.setRootVal(int(i))
parent = pstack.pop() # 出栈上升
currentTree = parent
elif i in ['+', '-', '*', '/']:
currentTree.setRootVal(i)
currentTree.insertRignt('')
pstack.push(currentTree)
currentTree = currentTree.getRightChild()
elif i == ')':
currentTree = pstack.pop() # 出栈上升
else:
raise ValueError
return eTree
表达式解析树求值
由于二叉树BinaryTree是一个递归数据结构, 自然可以用递归算法来处理
求值函数evaluate的递归三要素
- 基本结束条件:叶节点是最简单的子树,没有左右子节点,其根节点的数据项即为子表达式树的值
- 缩小规模:将表达式树分为左子树、右子树,即为缩小规模
- 调用自身:分别调用evaluate计算左子树和右子树的值,然后将左右子树的值依根节点的操作符进行计算,从而得到表达式的值
一个增加程序可读性的技巧:函数引用
import operator
op= operator.add
代码
def evaluate(parseTree):
opers = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv
}
# 缩小规模
leftC = parseTree.getLeftChild()
rightC = parseTree.getRightChild()
if leftC and rightC:
fn = opers[parseTree.getRootVal()]
# 递归调用
return fn(evaluate(leftC), evaluate(rightC))
else:
# 基本结束条件
return parseTree.getRootVal()
【数据结构与算法Python版学习笔记】树——二叉树的应用:解析树的更多相关文章
- 【数据结构与算法Python版学习笔记】引言
学习来源 北京大学-数据结构与算法Python版 目标 了解计算机科学.程序设计和问题解决的基本概念 计算机科学是对问题本身.问题的解决.以及问题求解过程中得出的解决方案的研究.面对一 个特定问题,计 ...
- 【数据结构与算法Python版学习笔记】目录索引
引言 算法分析 基本数据结构 概览 栈 stack 队列 Queue 双端队列 Deque 列表 List,链表实现 递归(Recursion) 定义及应用:分形树.谢尔宾斯基三角.汉诺塔.迷宫 优化 ...
- 【数据结构与算法Python版学习笔记】递归(Recursion)——定义及应用:分形树、谢尔宾斯基三角、汉诺塔、迷宫
定义 递归是一种解决问题的方法,它把一个问题分解为越来越小的子问题,直到问题的规模小到可以被很简单直接解决. 通常为了达到分解问题的效果,递归过程中要引入一个调用自身的函数. 举例 数列求和 def ...
- 【数据结构与算法Python版学习笔记】树——相关术语、定义、实现方法
概念 一种基本的"非线性"数据结构--树 根 枝 叶 广泛应用于计算机科学的多个领域 操作系统 图形学 数据库 计算机网络 特征 第一个属性是层次性,即树是按层级构建的,越笼统就越 ...
- 【数据结构与算法Python版学习笔记】树——利用二叉堆实现优先级队列
概念 队列有一个重要的变体,叫作优先级队列. 和队列一样,优先级队列从头部移除元素,不过元素的逻辑顺序是由优先级决定的. 优先级最高的元素在最前,优先级最低的元素在最后. 实现优先级队列的经典方法是使 ...
- 【数据结构与算法Python版学习笔记】树——平衡二叉搜索树(AVL树)
定义 能够在key插入时一直保持平衡的二叉查找树: AVL树 利用AVL树实现ADT Map, 基本上与BST的实现相同,不同之处仅在于二叉树的生成与维护过程 平衡因子 AVL树的实现中, 需要对每个 ...
- 【数据结构与算法Python版学习笔记】树——二叉查找树 Binary Search Tree
二叉搜索树,它是映射的另一种实现 映射抽象数据类型前面两种实现,它们分别是列表二分搜索和散列表. 操作 Map()新建一个空的映射. put(key, val)往映射中加入一个新的键-值对.如果键已经 ...
- 【数据结构与算法Python版学习笔记】树——树的遍历 Tree Traversals
遍历方式 前序遍历 在前序遍历中,先访问根节点,然后递归地前序遍历左子树,最后递归地前序遍历右子树. 中序遍历 在中序遍历中,先递归地中序遍历左子树,然后访问根节点,最后递归地中序遍历右子树. 后序遍 ...
- 【数据结构与算法Python版学习笔记】查找与排序——散列、散列函数、区块链
散列 Hasing 前言 如果数据项之间是按照大小排好序的话,就可以利用二分查找来降低算法复杂度. 现在我们进一步来构造一个新的数据结构, 能使得查找算法的复杂度降到O(1), 这种概念称为" ...
随机推荐
- 20210804 noip30
考场 第一眼感觉 T1 是状压 DP,弃了.T2 好像也是 DP???看上去 T3 比较可做. 倒序开题.T3 暴力是 \(O(pn\log p)\)(枚举 \(x\),二分答案,看能否分成合法的不超 ...
- Qt 程序发布以及打包成exe安装包
一.简述 Qt 项目开发完成之后,需要打包发布程序,而因为用户电脑上没有 Qt 配置环境,所以需要将 release 生成的 exe 文件和所依赖的 dll 文件复制到一个文件夹中,然后再用 Inno ...
- Appium问题解决方案(10)- Original error: Swipe did not complete successfully
背景 从搜索页面返回首页之后,执行 swipe 滑动操作,但是报错了,如上图 解决方法 只需要在第一次 swipe 之前加个 sleep,强制等待即可 备注 这种解决方案其实不好,强制等待能少用就少 ...
- DHCP 协议及其交互过程
1. DHCP用途简介: DHCP服务应用于大型局域网络中,使网络中的主机自动获取IP地址,网关,DNS服务器等信息,能够提升IP地址的利用率.一般情况下,我们的家用.公司.公共场合使用的路由器都具有 ...
- K8S 简介
K8S架构与组件 kubectl: 是一个客户端管理工具,直接管理API server,提供请求给API server,中间有auth认证.用户使用kubectl命令来请求API Server接口完成 ...
- Git--生成公钥和私钥并添加gitlab访问权限
Git配置 打开git bash 执行以下命令 git config --global user.name 用户名 git config --global user.email 邮箱 ssh-keyg ...
- ARM架构安装ubuntu系统
一.简介 arm开发板制作系统是比较麻烦,不论使用busybox还是yocto制作根文件系统对新手都比太友好,除非深度定制,否则使用ubuntu系统既可以满足,把更多的精力放在应用开发上. 二.准备材 ...
- 【C++周报】第一期2021-8-1
[C++周报]第一期 2021-8-1 这一期我们来看这道题目:https://vijos.org/p/1058 这道题是一道非常好的模拟题.题目如下: 描述 我们用文本处理器来处理一个特殊的文本文件 ...
- Shell系列(21)- 字符截取命令printf
作用 printf是标准格式输出命令,控制输出格式,不会自动加入换行符.awk会用到该条命令 命令 printf '输出类型输出格式' 输出内容 #''双引号不能少,输出类型和输出格式之间没有空格 输 ...
- js中date类型的格式转化为yyyy-MM-dd HH:mm:ss的String类型
在vue中或其他框架中可以在Date的原型链中添加Format的方法,如ruoyi可以写在main.js中更好,如果写在utils还需要去导入包. 正常的js直接放到utils.js就好 Date.p ...