计算机求解算术表达式,一种自然的方法是采用表达式树。
表达式树是一种二叉树,它的结点包含两种类型的对象:操作符和终值。
操作符是拥有操作数的对象,而终值是没有操作数的对象。
表达式树的思想:存储在父结点中的操作符,其操作数由其子结点延伸出来的子树组成。操作数也可能就是终值,或者它们本身也可能是其他的表达式。表达式在子树中展开,终值驻留在叶子结点中。
这种组织方式的好处是通过表达式树可以使我们非常容易的将一个表达式转换为3种常见的表示形式:前缀、中缀和后缀。
要获得这些表示形式,我们只需要按照前序、中序或者后序的遍历方式周游表达式树的结点即可。
如图所示,按照前序的方式遍历树,得到的前缀表达式为:X / - 74 10 32 + 23 17。
要计算一个前缀表达式,我们将每个操作符和紧跟在后面的两个操作数用圆括号括起来。因此这个前缀表达式可转化为:
( X ( / ( - 74 10) 32 ) ( + 23 17 )) = 80
中缀表达式是我们在数学中学到的最为熟悉的表达方式,但它们并不适合用计算机来处理。 如果我们把图中的树按照中序遍历的方式遍历,我们可以得到中缀表达式:74 - 10 / 32 X 23 + 17 。
注意中缀表达式的一个问题在于它们不能标识出计算的顺序,而前缀表达式和后缀表达式都可以做到。但是,我们可以在遍历树的过程中通过将每一部分的表达式都加上圆括号来修正这个问题。全部加完括号后,这个中缀表达式可以转化为:
(((74-10)/32 X (23+17)) = 80
后缀表达式非常适合于用计算机来处理。如果把图中的树按照后序遍历的方式遍历,就可以得到后缀表达式:74 10 - 32 / 23 17 + X。
要计算一个后序表达式,将每个操作符与紧接在其前面的两个操作数用圆括号括起。这样,后缀表达式将转化为:
(((74 10 -) 32 / ) ( 23 17 +) X) = 80
后缀表达式适合于计算机处理的一个原因是它们能够非常容易通过 抽象栈状态机(abstract stack machine)的方式来进行计算。按照抽象状态机的方式来处理一个后缀表达式,将采用如下步骤:首先,从左到右遍历表达式,将值压入栈中直到遇到一个操作符为止。然后,该操作符所需要的操作数被弹出栈,将操作符施加于操作数上并将结果重新压入栈中。这个过程将一直重复直到整个表达式都处理完毕。到那时,表达式的最终结果就是唯一还留在栈中的元素(如下图所示)。
代码示例1说明 了如何通过表达式树中存储的表达 式生成前缀、中缀和后缀表达式。基于这一目的,提供了3个函数:preorder、inorder、postorder。它们分别采用前序、中序、后序的方式来遍历表达式树。每个函数都接受两个参数node和list。
开始遍历时,将参数node设置为希望进行遍历的表达式树的根结点。连续的递归调用会将node设置为将要子树的根结点。初次每个函数调用时,还会把一个经过list_init初始化过的空链表传给参数list。对于每次的遍历,按照访问结点的顺序把它们加入链表list中。当首个递归调用最终返回时,list就分别包含按照前序、中序、后序方式遍历的结点。
示例1:遍历二叉树的实现函数
/*traverse.c*/
#include "list.h"
#include "traverse.h"
/*preorder 前序遍历*/
int perorder(const BiTreeNode *node,Lis list)
{
/*加载列表与树的前序列表*/
if(!bitree_is_eob(node))
{
if(list_ins_next(list,list_tail(list),bitree_data(node)) != 0)
return -1;
if(!bitree_is_eob(bitree_left(node)))
if(preorder(bitree_left(node),list) !=0 )
return -1;
if(!bitree_is_eob(bitree_right(node))
if(preorder(bitree_right(node),list) !=0 )
return -1;
}
return 0;
}
/*inorder 中序遍历*/
int inorder(const BiTreeNode *node,List *list)
{
/*加载列表与树的中序列表*/
if(!bitree_is_eob(node))
{
if(!bitree_is_ebo(bitree_left(node)))
if(inorder(bitree_left(node),list) != 0 )
return -1;
if(list_ins_next(list,list_tail(list),bitree_data(node))!=0)
return -1;