当前课程知识点:数据结构(上) > 第四章 栈与队列 > (c4)栈应用:中缀表达式求值 > 04C4-2 构思
其实,在这些工具背后
所蕴含的算法都大同小异
你应该还记得我们的括号匹配算法
对于任何的一个表达式
我们总是试图在其中找到
一对彼此紧邻
也因此相互配对的括号
我们的算法原理是
将这样一对括号删去
从而在剩余表达式与原先表达式
在是否匹配上互为
充要条件的前提下
使得问题的规模
也就是括号的对数 有所减少
这也就是我们所说的decrease and conquer策略
在这里 我们依然要在表达式中
寻找一个能够优先计算的子串
并且对它进行计算
然后将计算所得的数值
重新放置在这个位置上
经过如此的转换之后
新的表达式的数值
与原表达式的数值保持一致
同时如果我们将一个
表达式的复杂度
定义为其中包含的运算符的数目
那么这样一个过程
依然可以视作是一个
减而治之的过程
也就是说 这个算法具有单调性
最终将消除掉所有的运算符
从而得到最终的数值
我们来看一个具体的实例
最初的表达式列在最底层
总共包含1个 2个
3个 4个运算符
在所有这些运算符中 我们可以发现
乘号是可以优先计算的
也就是说 这个乘号随同两个运算数
以及表示优先级的一对括号
整体地可以认为是我们刚才所说的
一个局部可以优先计算的子表达式
既然这个表达式可以运算
我们不妨对它进行求值
并且在整个表达式中
将这个可以优先计算的子表达式
替代为它所对应的数值
我们可以看到
经过这样一步转换之后
问题的规模
也就是表达式中的运算符
减少了一个单位
接下来 我们可以
继续考察这个表达式
并且同样可以找到一个
可以优先计算的运算符乘方
因此同样地 取出这个运算符
所需要的两个操作数
对这个子表达式进行求值
并且代之以计算出的数值
以下同理
我们继续找到一个
可以优先计算的子表达式
对应的运算符以及运算数
并且同样地 代之以它所对应的数值
直到最后
只剩唯一的一个运算符
可以直截了当地进行运算
并且把结果作为最终的输出返回
从而完成整体的表达式求值
这样一个计算过程
虽然在纸面上简便易行
但是如果面对比较长
甚至非常长的表达式
就将碰到很大的困难
这个困难就在于我们很难
至少现在是很难定位当前
可以计算的那个运算符
如果我们以一种线性扫描的次序
来处理这个表达式
每当扫到一个运算符的时候
都未必能够确认
它已经是可以计算的
也就是说 我们的计算次序
未必与扫描的次序完全一致
如图所示 对于这样的一类问题
一种行之有效的办法
就是借助栈结构
是的 我们只需将所有
已经扫描过的部分
保存为一个栈
在所有已经扫描过的部分中
有一些是已经经过判断以后
能够及时处理的
也就是经过判断
能够在局部具有足够高的优先级
并且已经计算过的部分
而已经扫描过
但是还不足以判断能够计算的部分
将通过这个栈被缓冲起来
而我们的策略就是蚕食似地逐步地
将尚未扫描的部分扫描并且处理掉
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)计算
--演示
--(a)计算--作业
-(b)计算模型
-(b)计算模型--作业
-(c)大O记号
-(c)大O记号--作业
-(d)算法分析
-(d)算法分析--作业
-(e)迭代与递归
-(e)迭代与递归--作业
-(xc)动态规划
-- 演示
-(xc)动态规划--作业
-本章测验--作业
-(a)接口与实现
--02A-5 复制
-(a)接口与实现--作业
-(b)可扩充向量
-(b)可扩充向量--作业
-(c)无序向量
--02C-1 概述
--02C-3 插入
--02C-6 查找
--02C-8 遍历
-(c)无序向量--作业
-(d1)有序向量:唯一化
-(d1)有序向量:唯一化--作业
-(d2)有序向量:二分查找
-(d2)有序向量:二分查找--作业
-(d3)有序向量:Fibonacci查找
-(d3)有序向量:Fibonacci查找--作业
-(d4)有序向量:二分查找(改进)
-(d4)有序向量:二分查找(改进)--作业
-(d5)有序向量:插值查找
-第二章 向量(下)--(d5)有序向量:插值查找
-(e)起泡排序
--02E-2 改进
--02E-3 反例
-(e)起泡排序--作业
-(f)归并排序
-(f)归并排序--作业
-本章测验--作业
-(a)接口与实现
--03A-4 实现
-(a)接口与实现--作业
-(b)无序列表
--03B-2 查找
-(b)无序列表--作业
-(c)有序列表
--03C-3 查找
-(c)有序列表--作业
-(d)选择排序
--03D-1 构思
--03D-2 实例
--03D-3 实现
--03D-4 推敲
--03D-6 性能
-(d)选择排序--作业
-(e)插入排序
--03E-1 经验
--03E-2 构思
--03E-3 对比
--03E-4 实例
--03E-5 实现
-(e)插入排序--作业
-(xd)习题辅导:LightHouse
-本章测验--作业
- (a)栈接口与实现
--04A-1 栈
--04A-2 实例
--04A-3 实现
- (a)栈接口与实现--作业
-(c1)栈应用:进制转换
-第四章 栈与队列--(c1)栈应用:进制转换
-(c2)栈应用:括号匹配
-(c2)栈应用:括号匹配--作业
-(c3)栈应用:栈混洗
-第四章 栈与队列--(c3)栈应用:栈混洗
-(c4)栈应用:中缀表达式求值
-(c4)栈应用:中缀表达式求值--作业
-(c5)栈应用:逆波兰表达式
-第四章 栈与队列--(c5)栈应用:逆波兰表达式
-(d)队列接口与实现
--04D-1 接口
--04D-2 实例
--04D-3 实现
-第四章 栈与队列--本章测验
-(a)树
--05A-1 动机
--05A-2 应用
-(a)树--作业
-(b)树的表示
--05B-2 父亲
--05B-3 孩子
-第五章 二叉树--(b)树的表示
-(c)二叉树
-(c)二叉树--作业
-(d)二叉树实现
-(d)二叉树实现--作业
-(e1)先序遍历
-(e1)先序遍历--作业
-(e2)中序遍历
-第五章 二叉树--(e2)中序遍历
-(e4)层次遍历
-第五章 二叉树--(e4)层次遍历
-(e5)重构
-(e5)重构--作业
-本章测验--作业
-(a)概述
-(a)概述--作业
-(b1)邻接矩阵
-(b1)邻接矩阵--作业
-(c)广度优先搜索
--06C-2 策略
--06C-3 实现
--06C-5 实例
-(c)广度优先搜索--作业
-(d)深度优先搜索
--06D-1 算法
--06D-2 框架
--06D-3 细节
-(d)深度优先搜索--作业
-第六章 图--本章测验