通过表达式二叉树进行算术表达式求值,输入一个算术表达式,其中操作数必须为实数,运算符包括加、减、乘、除、小(圆)括号,还可以将此算术表达式所对应的表达式二叉树以文件的形式保存,同时能从文件中读入保存的表达式二叉树,同时还能够检查出绝大部分的语法错误。
/*** headfile.h ***/
#include
<
cstring
>
#include
<
fstream.h
>
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
#include
"
ToExpTree.h
"
/*** ToExpTree.h ***/
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
#ifndef TOEXPTREE_H
#define
TOEXPTREE_H
//
#include<iostream>
#include
<
fstream
>
#include
<
cstring
>
#define
MAX 30
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
struct
tree_node...
...
{
bool fc; //true is float,false is char
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
union ......{
float number; //数
char ch; //操作符
};
struct tree_node *left_child,*right_child;
}
;
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
class
ToExpTree...
...
{
public:
ToExpTree(); //缺省构造函数
tree_node * CreatTree(void); //后缀表达式建表达式二叉树
void TravPre(tree_node *&head); //先序遍历二叉树
void TravIn(tree_node *&head); //中序遍历二叉树
void TravPost(tree_node *&head); //后序遍历二叉树
bool divideop(char (&ach)[100]);
//将操作数和操作符从数组中提取出来,将其地址依次保存pnode_in中
//返回值为true时说明该表达式没错,为false时则有误
void InToPostfix(void);//中缀表达式转为后缀表达式
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
void display(tree_node *(&pnode)[MAX]); /**//**//**/////验证函数
void GiveHead(tree_node *); //给tree_head 赋值
tree_node *get(void); //提供tree-head的外部接口
float GetResult(tree_node *&head); //根据二叉树计算表达的值
bool Save(void); // 保存
bool Read(void); //读文件
private:
tree_node *pnode_in[MAX],*pnode_post[MAX],*pnode_tree[MAX],*tree_head;
//中缀栈,后缀栈,建树时用的栈,树的头结点
int pnode_in_num; //做pnode的下标,及记录pnode的存储个数
ofstream outfile;
ifstream infile;
char gettop(char (&ach)[100],int &m);//取栈顶元素
tree_node *& gettop(tree_node *(&pnode)[MAX],int &m); //取栈顶元素
bool push(tree_node *(&pnode)[MAX],tree_node *&a_node,int &m);//入栈
bool push(char (&ach)[100],char ch,int &m); //入栈,重载
tree_node * pop(tree_node *(&pnode)[MAX],int &m); //出栈
char pop(char (&ach)[100],int &m);//出栈,重载
bool CmpOp(char a,char b);//比较操作符的优先级
bool ToFloat(char **ct,float &ft,int &ht);
//将字符形式的数转换为float型数,若表达式有错误,返回false
void visit(tree_node *&head); //输出结点
void savetree(tree_node *&head);//保存二叉树
void readtree(tree_node *&head);//读出二叉树的结构
}
;
#endif
/**** ToExpTree.cpp ****/
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
将操作数和操作符从数组中提取出来,将其地址依次保存pnode中
//
返回值为true时说明该表达式没错,为false时则有误
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/*#include<iostream>
#include<fstream>
#include"ToExpTree.h"
using std::cout;
using std::endl;
using std::cin;
using std::cerr;*/
#include
"
headfile.h
"
ToExpTree::ToExpTree()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
int i;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
for(i=0;i<MAX;i++)...{
pnode_in[i]=NULL;
pnode_post[i]=NULL;
pnode_tree[i]=NULL;
}
}
//
void ToExpTree::ToExpTree()
//
将字符形式的数转换为float型数,若表达式有错误,返回false
bool
ToExpTree::ToFloat(
char
**
ct,
float
&
ft,
int
&
ht)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
char *pt=*ct;
int zh=0,negative=1;
//zh用来暂存整数部分,ft暂存小数部分,n表示小数点后的位数,
//negative=1时表示正数,-1时表示负数
float fk;
ft=0; //ft复位
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(*pt=='-'||*pt=='+')...{
if(*pt=='-')negative=-1; //为负数
pt++;ht++;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
while(*pt>='0'&&*pt<='9')...{ //计算整数部分
zh=zh*10+(*pt-'0');
ht++;pt++;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(*pt!='.')...{ft=static_cast<float>(zh)*negative;*ct=pt;return true;} //当不是小数点时退出函数
pt++;
ht++;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
for(fk=1;*pt>='0'&&*pt<='9';pt++,ht++)...{
fk*=0.1;
ft=ft+(*pt-'0')*fk;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(*pt=='.')...{*ct=pt;return false;} //有多个小数点的错误
ft=(zh+ft)*negative;
*ct=pt;
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
bool
ToExpTree::divideop(
char
(
&
abc)[
100
])
...
{
tree_node *p;
char *cp,*cq;
int n=100;
bool qian=false;
//true表示前面为数或')',false则表示其他,用于检测表达式的正误.初始化为false
float operand;int hi=0;//hi计算数组的下标
int count=0; //用来计算括号是否匹配
pnode_in_num=0;//初始化pnode_in 的下标
cp=abc;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
while(*cp!=''&&hi<=n)...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(*cp>='0'&&*cp<='9'||*cp=='-'||*cp=='+')...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if((*cp=='-'||*cp=='+')&&hi!=0)...{
cq=cp-1;
if(*cq=='(');
else goto next;
//如果'+''-'表示的不是正负号时则跳出
}
if(!ToFloat(&cp,operand,hi))return false;//表达式中数的表达有错误
p=new tree_node;
p->fc=true;
p->number=operand;
qian=true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
else if(*cp=='+'||*cp=='-'||*cp=='*'||*cp=='/'||*cp=='('||*cp==')')...{
next: if(qian==false&&*cp!='('&&*cp!=')')return false;//检测诸如a**b的表达式错误
qian=false;
if(*cp!='('&&hi==0)return false; //当第一个不是数字或'('时,表达式错误
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(*cp=='(')...{
if(hi!=0&&*(cp-1)>'0'&&*(cp-1)<'9')return false;
count++;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
else if(*cp==')')...{
if(count==0||*(cp+1)!=''&&*(cp+1)>='0'&&*(cp+1)<='9')return false;
//右括号在前错误以及右括号后面直接跟操作数的错误
count--; //在最后若count不为0,则表达式错误,括号不匹配
qian=true;
}
p=new tree_node;
p->fc=false;
p->ch=*cp;
cp++;hi++;
}
else return false; //表达式中出现其他无关字符的 错误
pnode_in[pnode_in_num++]=p;
if(pnode_in_num>MAX+1)return false; //存储空间不足错误
}
cp--;
if(*cp=='+'||*cp=='-'||*cp=='*'||*cp=='/'||count!=0)
return false;//最后一个字符为操作符的错误或括号不匹配的错误
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
void
ToExpTree::InToPostfix(
void
)
//
中缀转后缀
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
char rch,top;
tree_node *p,*pnode_while[MAX];
int an=0,pn_trav=0,pn_sav=0; //分别做pnode_while下标,pnode_in的遍历及存储下标
for(int i=0;i<MAX;i++)pnode_while[i]=NULL; //初始化数组pnode_while
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
while(pn_trav<pnode_in_num)...{
p=pnode_in[pn_trav++];
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(p->fc)...{push(pnode_post,p,pn_sav);continue;} //为数时直接入栈
rch=p->ch;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(!an||rch=='(')...{push(pnode_while,p,an);continue;} //当为第一个操作符或是左括号时直接入栈
top=(gettop(pnode_while,an))->ch;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(top=='('&&rch!=')')...{push(pnode_while,p,an);continue;}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if (!CmpOp(top,rch)) ...{push(pnode_while,p,an);continue;}//栈顶操作符的优先级比即将入栈的要低
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
while(1)...{ //栈顶的优先级比即将入栈的要高或相等
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(rch==')'&&top=='(')...{
pop(pnode_while,an);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
break;} /**//
push(pnode_post,pnode_while[an-1],pn_sav);
pop(pnode_while,an);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(!an)...{push(pnode_while,p,an);break;}
top=(gettop(pnode_while,an))->ch;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(top=='('&&rch!=')')...{push(pnode_while,p,an);break;}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(!CmpOp(top,rch))...{push(pnode_while,p,an);break;}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
while(an>0)...{
p=pop(pnode_while,an);
push(pnode_post,p,pn_sav);
}
cout<<endl;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
bool
ToExpTree::push(tree_node
*
(
&
pnode)[MAX],tree_node
*&
a_node,
int
&
m)
...
{
if(m<0||m>MAX)return false;
pnode[m++]=a_node;
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
bool
ToExpTree::push(
char
(
&
ach)[
100
],
char
ch,
int
&
m)
...
{
if(m<0||m>100)return false;
ach[m++]=ch;
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
tree_node
*
ToExpTree::pop(tree_node
*
(
&
pnode)[MAX],
int
&
m)
...
{
if(m<0||m>MAX)return NULL;
return pnode[--m];
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
char
ToExpTree::pop(
char
(
&
ach)[
100
],
int
&
m)
...
{
if(m<0||m>100)return 0;
return ach[--m];
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
tree_node
*&
ToExpTree::gettop(tree_node
*
(
&
pnode)[MAX],
int
&
m)
...
{
//if(m<0||m>MAX)return NULL;
return pnode[m-1];
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
char
ToExpTree::gettop(
char
(
&
ach)[
100
],
int
&
m)
...
{
if(m<0||m>100)return 0;
return ach[m-1];
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
bool
ToExpTree::CmpOp(
char
a,
char
b)
...
{
//操作符(+-*/)的优先级比较函数,返回true,前者比后着大或者相等
if(a==')')return false; //右括号的优先级最低
if(b=='(')return false; //左括号的优先级最高
if(a=='+'||a=='-')
if(b=='*'||b=='/')return false;
return true;
}
tree_node
*
ToExpTree::CreatTree(
void
)
//
后缀表达式建表达式二叉树
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
tree_node *left,*right,*head,*htr;
int i=0,j=0;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
while((htr=pnode_post[i++])!=NULL)...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(htr->fc)...{
push(pnode_tree,htr,j);
htr->left_child=NULL;
htr->right_child=NULL;
continue;
}
right=pop(pnode_tree,j);
left=pop(pnode_tree,j);
head=htr;
head->left_child=left;
head->right_child=right;
push(pnode_tree,head,j);
}
return head;
}
void
ToExpTree::TravPre(tree_node
*&
head)
//
先序遍历二叉树
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(head) ...{
visit(head);
TravPre(head->left_child);
TravPre(head->right_child);}
return;
}
void
ToExpTree::TravIn(tree_node
*&
head)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(head)...{
if(head->fc) visit(head);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
else...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(!(head->left_child->fc)&&!CmpOp(head->left_child->ch,head->ch))...{
//左子树的优先级比头结点的优先级要低时
cout<<'(';
TravIn(head->left_child);
cout<<')';
}
else TravIn(head->left_child);
visit(head);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(!(head->right_child->fc)&&!CmpOp(head->right_child->ch,head->ch))...{
//右子树的优先级比头结点的优先级要低时
cout<<'(';
TravIn(head->right_child);
cout<<')';
}
else TravIn(head->right_child);
}
}
}
void
ToExpTree::TravPost(tree_node
*&
head)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(head)...{
TravPost(head->left_child);
TravPost(head->right_child);
visit(head);
}
return;
}
void
ToExpTree::visit(tree_node
*&
head)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
if(head->fc)cout<<head->number<<" ";
else cout<<head->ch<<" ";
return;
}
void
ToExpTree::display(tree_node
*
(
&
pnode)[MAX])
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
int i;
for(i=0;i<MAX&&pnode[i]!=NULL;
i++)
visit(pnode[i]);
return;
}
void
ToExpTree::GiveHead(tree_node
*
p)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
tree_head=p;
return;
}
tree_node
*
ToExpTree::
get
(
void
)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
return tree_head;
}
float
ToExpTree::GetResult(tree_node
*&
head)
//
根据二叉树计算表达式的值
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
float result=0,Lre=0,Rre=0,swp=0;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(!(head->fc))...{
if(head->left_child->fc) Lre=head->left_child->number;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
else ...{swp=Rre;Lre=GetResult(head->left_child);Rre=swp;}
if(head->right_child->fc)Rre=head->right_child->number;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
else ...{ swp=Lre; Rre=GetResult(head->right_child); Lre=swp;}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(1)...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
switch(head->ch)...{
case '*': result=Lre*Rre;break;
case '/': result=Lre/Rre;break;
case '+': result=Lre+Rre;break;
case '-': result=Lre-Rre;break;
}
}
}
return result;
}
bool
ToExpTree::Save(
void
)
//
保存二叉树
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
char filename[100];
cout<<endl<<"Please input the filename to save:";
cin>>filename;
outfile.open(filename);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(!outfile)...{
cerr<<"Cannot open the file ""<<filename<<""for input,it maybe doesn't exist"<<endl;
return false;
}
savetree(tree_head);
outfile.close();
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
void
ToExpTree::savetree(tree_node
*&
head)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(head)...{
if(head->fc)outfile<<" "<<'T'<<" "<<head->number<<endl; //True
else outfile<<" "<<'F'<<" "<<head->ch<<endl; //False
if(!head->left_child)outfile<<" # "<<endl; //当其左子树为空时输出#
else savetree(head->left_child);
if(!head->right_child)outfile<<" # "<<endl; //当其右子树为空时输出#
else savetree(head->right_child);
}
return;
}
bool
ToExpTree::Read(
void
)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
char filename[100];
cout<<endl<<"Please input the filename to read:";
cin>>filename;
infile.open(filename);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(!infile)...{
cerr<<"Cannot open the file ""<<filename<<""for read,it maybe doesn't exist"<<endl;
return false;
}
readtree(tree_head);
infile.close();
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
void
ToExpTree::readtree(tree_node
*&
head)
...
{
char cht;
infile>>cht;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(cht=='#')...{head=NULL;return;}
head=new tree_node;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(cht=='T')...{
head->fc=true;
infile>>head->number;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
else if(cht=='F')...{
head->fc=false;
infile>>head->ch;
}
readtree(head->left_child);
readtree(head->right_child);
return;
}
/****** main.cpp *****/
#include
"
headfile.h
"
int
main(
void
)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
...
{
char s[100];int seh;
char ar;
tree_node *p;
float ff;
ToExpTree *ah=new ToExpTree;
start: cout<<"Do you want to input directly or load a saved file:"<<endl;
cout<<"1:input directly;"<<endl;
cout<<"2:load a saved file;"<<endl;
cout<<"3:Exit;"<<endl<<"please select:";
cin>>seh;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(seh==3)......{system("pause");return 0;}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
else if(seh==1)......{
cout<<"intput a expression:";
cin>>s;cout<<endl;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if(!ah->divideop(s))......{cout<<"The expression is error!!!"<<endl;goto start;}
ah->InToPostfix();
p=ah->CreatTree();
ah->GiveHead(p);
p=ah->get();
}
else if(seh==2)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
......{if(!ah->Read()) goto start;}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
else ......{cout<<"input error!"<<endl;goto start;}
p=ah->get();
cout<<" 前序遍历:";
ah->TravPre(p);
cout<<endl<<"中序遍历:";
ah->TravIn(p);
cout<<endl<<"后序遍历:";
ah->TravPost(p);
ff=ah->GetResult(p);
cout<<endl<<"计算结果:"<<ff;
cout<<endl<<"是否保存二叉树?(Y/N):";
cin>>ar;
if(ar=='y'||ar=='Y')
if(ah->Save())cout<<endl<<"The ExpTree had been save correctly!";
return 0;
}
正好文档还在电脑里面,这里也就顺便把其中的主要算法也贴出来吧:
(1)字符数组转换成表达式(由函数divideop完成):从数组中读入一个字符,若这个字符是数字字符的话,则进入ToFloat函数,直到下一个字符是操作符的时候才退出ToFloat函数,此时该函数返回一个float型数,得到一个操作数,然后再根据tree_node的规则完成fc的值,入栈(pnode_in)。如果读入的字符是“+”、“-”则首先应该判断这两个符号是正负号还是操作符的加减号,如果是正负号,则同样进入ToFloat,返回一个操作数,入栈(pnode_in);如果是加减号的话,则直接完成fc的赋值,再入栈。当读到“(”、“)”、“*”、“/”的时候跟加减号一样,直接入栈(pnode_in)。若是其他字符则直接退出divideop,返回false,说明该表达式有错误。同时在函数的适当的地方都加了一些检测表达式是否正确的语句,可以检测到绝大部分的表达式的错误。比如:“)”在“(”前面,两个数中间没有操作符,括号和数中间没有操作符的问题等。
(2)中缀转后缀(InToPostfix实现):此时表达式存在pnode_in中,转换后的后缀表达式将存在pnode_post中,在InToPostfix中额外定义了一个辅助堆栈(pnode_while),从pnode_in中读入。当读到一个操作数的时候立即把它入栈(pnode_post),当读到操作符时先入栈(pnode_while),当遇到“(”时也应该先入栈(pnode_while),此时从一个空栈开始计算。如果见到“)”,则将栈(pnode_while)中元素弹出,将弹出的符号入栈(pnode_post),直到遇到对应的“(”时,此时直接“(”从pnode_while中弹出而不必再入栈。如果遇到其他操作符,如果栈顶(pnode_while)元素优先级必将入栈(pnode_while)的元素的优先级高或相等,则栈顶(pnode_while)元素出栈,入栈(pnode_post),继续比较直到栈顶(pnode_while)的元素的优先级比它低为止,将该操作符入栈(pnode_while)。(“(”的优先级最高,当遇到“)”时才移走)。
(3)根据后缀表达式建立表达式二叉树(CreatTree实现):此时从pnode_post中读数,当此时用pnode_tree做辅助堆栈,当从pnode_post中读入的是操作数是直接入栈,直到遇到操作符,操作符先不入栈,依次出栈两个结点,先出来的做右操作数,后出来的做左操作数,然后将该操作符的left_child指向左操作数,right_child指向右操作数,最后将该操作符所在结点入栈。
(4)先序遍历和后序遍历:跟一般二叉树的先序和后序遍历一样,都是直接用一个递归即成。
(5)中序遍历(TravIn实现):用的也是递归,如果头结点为空,退出。如果头结点存的是操作数,则先访问头结点,退出;否则如果头结点的左子树是操作符且其优先级比头结点的要低,则先输出“(”,然后以头结点的左子树为参数进入递归,然后再输出“)”。如果左子树存的是操作数的话,直接进入递归。然后访问头结点。接下来就是处理右子树了,其方法跟处理左子树是类似的。
用这个方法就可以避免括号的冗余。
(6)保存(Save):事实上就是一个先序遍历的过程,当读到的是操作符时,先输出F(表示接下来的是一个操作符,char),然后再输出操作符。如果它的左子树为空,则输出“#”(表示为空),否则就以左子树为参数进入递归。然后就是右子树了,如果右子树为空,则输出“#”,否则就以右子树为参数进入递归。
(
7
)读取文件(
Read
):读取也是以先序来读的,当读到的字符是
F
时,表示接下来的是操作符;如果读到的字符是
T
时,表示接下来的时操作数,这样就完成了一个结点的读取。如果读到的是“
#
”时,表示该树为空。
参考资料
1、《数据结构(C语言版)》 严蔚敏 吴伟民 清华大学出版社
2、《数据结构与算法分析-C语言描述》(美)Mark Allen Weiss著 冯舜玺 译 机械工业出版社
3、《C++Primer》 Stanley B.Lippman著 潘爱民 译 中国电力出版社
PS:其实上面 的
字符数组转换成表达式写得过于复杂了,后来无意中见过一个函数ungetc,如果使用这个函数的话那这一功能的代码将大大简化,可惜我将对算术表达式正确性的检查也写在这一功能里面了,显得比较乱,所以也就没有更新这一功能了。