王朝网络
分享
 
 
 

关于用优先级队列和树解决中缀表达式计算的一点比较

王朝other·作者佚名  2006-04-14
宽屏版  字体: |||超大  

最近我修改了我以前写的数学表达式计算器。以前那个是用最基本的优先级队列实现的,如果只是进行少量的式子计算,效率还勉强可以。但是,如果用于函数的作图,效率真的不敢恭维。

我先讲一下以前是怎么用优先级队列实现的。

1、接受用户直接输入的算式。如: sin(cos(tan(log[45.4^3-3]&(Pi*3.4)))/3.4*e*c*3.4E4)

2、对这个算式进行词法分析。

3、语法分析。首先分析算式中有可能出现的书写错误。然后创建数据数组,用于记录数值,如:45.4、3.4等。最后,把每一个函数单元(sin、cos等)用一个结构Datamark包装。

struct DataMark

{

int m_headmark; //操作数在数据数组中的位置

int m_tailmark; //操作数在数据数组中的位置

DataOperator m_name; //记录操作符的类别

DataQueue *m_childqueue; //用于处理括号的情况。如果这个节点是括号,则这个是保存这个括//号里面子算式的优先级队列。

PowerValue m_power; //运算符的优先级

DataMark() //构造函数

{

m_headmark = 0;

m_tailmark = 0;

m_childqueue = NULL;

m_name = O_NONETHISOPERATOR;

};

~DataMark() //析构函数

{

};

};

其中这个结构记录相关的优先级、函数名字(枚举)、操作数、每一个操作数数值在对应的数据数组中的下标。

4、把“函数单元”结构传入队列。

5、从优先级队列中按顺序弹出运算级最高的结构,分析函数类型,然后调用相应的自定义类成员函数进行计算。把每一步计算的结果传回数值数组并覆盖原来位置的值。单是把数据传回数据数组这一步复杂度就为O(n^2),其中n是数值的数量。

6、返回数组中第一个元素的值。该值就是算式的值。

明显,以前的方法虽然直观,但是对于要对同一个算式计算多次的情况(如函数作图器)就做了很多重复低效的工作。

所以,我从树结构中收到启发,从新写了一个计算器。例如,我们要计算这样一个算式:sin(4.3*Pi) – (4 *4 – 4 ) 在树结构是这样储存的:

Minus

sin

Minus

Multiply

4.3

Pi

Multiply

4

4

4

Minus

sin

Minus

Multiply

4.3

Pi

Multiply

4

4

4

Minus

sin

Minus

Multiply

4.3

Pi

Multiply

4

4

4

其中一些节点是储存操作的(具体是函数地址),如Multiply;而另一些如4就是储存数据的。具体过程是利用二叉树遍历的方法,从树的左下角元素开始,采用深度优先遍历树,同时遇到数值,并且如果其兄弟节点也是数据节点的话,就利用父节点A所储存的函数地址调用相关的函数计算,然后把结果保存在节点A中,这时候A就变成是数据节点,然后继续搜索下一个节点,采取同样的办法处理。就这样,当最后遍历回根节点就出现两种情况:1、根节点是函数节点:调用函数计算两个(或者一个)孩子的数据,最后返回。

2、根节点是数据节点:直接返回数值。

这里就出现一个问题,就是怎么建立这样的树呢。我是采用栈来实现的。具体和单纯用栈做中缀表达式求值很相似(本文后有简单说明),只是把从操作符栈弹出运算符那步骤换成是:先从操作符栈弹出运算符;然后从数据栈中弹出两个或一个数据(具体由操作符的结合数决定),并把它们连接到运算符节点中;最后再把这个运算符压到数据栈中,把它当作数据处理。 就这样,知道所有元素均成为树节点后,建立树的工作完成。

所以很明显,对于同一条式子来说,用上面的方法计算含有未知数X的函数式只需要作一次算式分析,对于每一个X只需要修改相应的节点,然后从新遍历一次树就行了。其实关键还是树这种结构能够反映数据计算的先后关系。

==================================

现在我引用书上的说法对用栈求中缀表达式的算法作简单说明。

中缀表达式求值算法用操作数栈(浮点数栈)来存放操作数和中间运算结果,另一个运算符栈存放运算符和可以使我们实现优先级的左括号,读入表达式是,将表达式元素压入各自的栈中。即遇到操作数时,将其压入操作数栈,而当运算需要时,将其从栈中弹出,而仅当当前栈中优先级大于或者等于当前的运算符优先级,才将运算符弹出,当执行完后才将运算符从栈中弹出,即当后续输入的运算符优先级小于或等于他的优先级或表达式结束时才弹出。运算符优先级分两次给定,第一次是读入时(称为读入优先级),第二次时压入栈后(称为栈优先级)。读入优先级和栈优先级比较,用于括号和右结合运算符。(我就讲这么多了,具体看数据结构吧)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有