1、- - 1一、需求分析【课程设计要求】【问题的描述】一个表达式和一棵二叉树之间,存在着自然的对应关系。写一个程序,实现基于二叉树表示的算术表达式 Expression 的操作。【基本要求】【一】 【必做部分】假设算术表达式 Expression 内可以含有变量(a-z),常量(0-9)和二元运算符(+,-,*,/,(乘幂) ) 。实现以下操作:(1)ReadExpr(E)以字符序列的形式输入语法正确的前缀表达式并构造表达式 E。(2)WriteExpr(E)用带括号的中缀表达式输出表达式 E。(3)Assign(V,c)实现对变量 V 的赋值(V=c) ,变量的初值为 0。(4)Value(E
2、)对算术表达式 E 求值。(5)CompoundExpr(p,E1,E2)构造一个新的复合表达式(E1)p(E2) 。【二】 【选做部分】(1)以表达式的原书写形式输入,支持大于 0 的正整数常量;(2)增加常数合并操作 MergeConst(E)合并表达式 E 中所有常数运算。例如,对表达式 E=(2+3-a)*(b+3*4)进行合并常数的操作后,求得 E=(5-a)*(b+12)(3)增加对求偏导数的运算 Diff(E,V)求表达式 E 对 V 的导数(4)在表达式内增加对三角函数等初等函数的操作。【测试数据】(1)分别输入 0;a;-91;+a*bc;+*5x2*8x;+*3*2x2x6
3、 并输出。(2)每当输入一个表达式后,对其中的变量赋值,然后对表达式求值二 、 【整体算法思想】一个表达式和一棵二叉树之间存在一一对应的关系。本程序我主要用前缀表达式建树,中序遍历并适当加括号实现中缀输出。具体操作即对树的程序进行处理,再输出。三、 【概要设计】1、数据类型的声明:在这个课程设计中,采用了链表二叉树的存储结构,以及两个顺序栈的辅助存储结构/*头文件以及存储结构*/#include- - 2#include#include#include#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW
4、 0typedef int Status;2、表达式的抽象数据类型定义ADT Expression数据对象 D:D 是具有数值的常量 C 和没有数值的变量 V;数据关系:R=|V,CD, 表示由运算符 P 结合起来的表达式 E基本操作:Status Input_Expr(操作结果:运算符运算求值,参数 opr1,opr2 为常量,opr 为运算符,根据不同的运算符,实现不同的运算,返回运算结果。Status Check(E)- - 3初始条件:表达式 E 存在;操作结果:检查表达式 E 是否还存在没有赋值的变量,以便求算数表达式 E 的值。long Value(E)初始条件:表达式 E 存在;
5、操作结果:对算术表达式求值,返回求到的结果。void CompoundExpr(P,printf(“n*“);printf(“n 1 输入正确的前缀表达式“);printf(“n 2 带括弧的中缀表示式输出“);printf(“n 3 对变量进行赋值“);printf(“n 4 对算数表达式求值“);printf(“n 5 构造一个新的复合表达式“);printf(“n 6 以表达式的原书写形式输入“);printf(“n 7 合并表达式中所有常数运算“);printf(“n 0 退出“);printf(“n*“);printf(“n 请输入你的选择“);choice=getche();ret
6、urn choice;在主函数中,采用多分支程序设计语句 switch()使程序产生不同的流向,从而达到实现课程设计的各个要求。void main()while(1)清屏;switch(主菜单)根据不同的选择,调用不同的操作函数,完成各个操作;2、本程序有四个模块,主程序模块,二叉树模块,两个顺序栈模块。四者的调用关系如下:- - 5主程序模块二叉树模块顺序栈 SqStack 模块顺序栈 SqStack1 模块主程序模块中的对于表达式的存储结构调用了二叉树模块,而在构造表达式的二叉树模块中又调用了顺序栈 SqStack 模块,主程序中在将原表达式形式输入表达式转换为前缀表达式操作中调用了顺序栈
7、 SqStack1 模块。四、 【详细设计】1、二叉树的存储类型/*二叉树结点类型*/typedef enumINT,CHARElemTag;/*INT 为整型数据 num,CHAR 为字符型数据 c*/typedef struct TElemTypeElemTag tag;/*INT,CHAR指示是整型还是字符型*/unionint num;/*tag=INT 时,为整型*/char c;/*tag=CHAR 时,为字符型*/; TElemType;/*二叉树的二叉链表存储表示 */typedef struct BiTNodeTElemType data;struct BiTNode *lc
8、hild,*rchild; /* 左右孩子指针 */BiTNode,*BiTree;二叉树的基本操作已经在构造表达式和表达式中的基本操作中根据不同的功能和实际情况修改了,详细见各个函数操作的算法设计。2、顺序栈的存储类型/*栈的顺序存储表示 */#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */#define STACKINCREMENT 2 /* 存储空间分配增量 */*两个顺序栈*/typedef struct SqStack- - 6SElemType *base; /* 在栈构造之前和销毁之后,base 的值为 NULL */SElemType *to
9、p; /* 栈顶指针 */int stacksize; /* 当前已分配的存储空间,以元素为单位 */SqStack; /* 顺序栈 SqStack */typedef struct SqStack1SElemType1 *base; /* 在栈构造之前和销毁之后,base 的值为 NULL */SElemType1 *top; /* 栈顶指针 */int stacksize; /* 当前已分配的存储空间,以元素为单位 */SqStack1; /* 顺序栈 SqStack1 */相关的基本操作见上面的“expression.h 文件的整体结构”的说明,详细的算法设计见附录的程序清单。3、表达式
10、的基本操作Status Input_Expr(char *string,int flag);/*以字符序列的形式输入语法正确的前缀表达式,保存到字符串 string*/*参数 flag=0 表示输出的提示信息是“请输入正确的前缀表示式:“*/*flag=1 表示输出的提示信息为“请以表达式的原书写形式输入正确表示式:“*/void judge_value(BiTree *E,char *string,int i);/*判断字符 stringi,如果是0-9常量之间,二叉树结点存为整型;否则,存为字符型*/Status ReadExpr(BiTree *E,char *exprstring);/
11、*以正确的前缀表示式并构造表达式 E*/Status Pri_Compare(char c1,char c2);/*如果两个字符是运算符,比较两个运算符的优先级,c1 比 c2 优先,返回 OK,否则返回 ERROR*/void WriteExpr(BiTree E);/*用带括弧的中缀表达式输入表达式*/void Assign(BiTree *E,char V,int c,int *flag);/*实现对表达式中的所有变量 V 的赋值(V=c),参数 flag 为表示是否赋值过的标志*/long Operate(int opr1,char opr,int opr2);/*运算符运算求值,参数
12、 opr1,opr2 为常量,opr 为运算符,根据不同的运算符,实现不同的运算,返回运算结果*/Status Check(BiTree E);/*检查表达式是否还存在没有赋值的变量,以便求算数表达式的值*/long Value(BiTree E);/*对算术表达式求值*/void CompoundExpr(char P,BiTree *E1,BiTree E2);/*构造一个新的复合表达式*/Status Read_Inorder_Expr(char *string,char *pre_expr);/*以表达式的原书写形式输入,表达式的原书写形式字符串 string 变为字符串pre_exp
13、r,后调用 reversal_string()函数反转得到前缀表达式 pre_expr*/void MergeConst(BiTree *E);- - 7/*常数合并操作函数,合并表达式 E 中所有常数运算*/4、主程序和其他伪码算法void main()while(1)switch(menu()case 1:/*输入正确的前缀表达式*/if(Input_Expr(Expr_String,0)输入正确的前缀表达式if(ReadExpr(printf(“n 表达式构造成功!“);case 2:/*带括弧的中缀表示式输出*/if(flag=1) WriteExpr(E);else printf(“
14、n 表达式未构造成功!请构造成功的表达式!“);case 3:/*对变量进行赋值*/if(flag=1)flushall();/*清理缓冲区*/V=getchar();scanf(Assign(else printf(“n 表达式未构造成功!请构造成功的表达式!“);case 4:/*对算数表达式求值*/if(flag=1)if(Check(E) result=Value(E); WriteExpr(E);printf(result);else printf(“n 表达式未构造成功!请构造成功的表达式!“);case 5:/*构造一个新的复合表达式*/if(flag=1)flushall();
15、/*清理缓冲区*/if(Input_Expr(string,1)if(Read_Inorder_Expr(string,Expr_String)/*按原表达式形式输入*/reversal_string(Expr_String);if(ReadExpr(P=getchar();CompoundExpr(P,- - 8else printf(“n 复合新的表达式失败!请按任意键返回主菜单!“);case 6:/*以表达式的原书写形式输入*/if(Input_Expr(string,1)if(Read_Inorder_Expr(string,Expr_String)reversal_string(E
16、xpr_String);if(ReadExpr(printf(“n 表达式构造成功!“);case 7:/*合并表达式中所有常数运算*/if(flag=1) MergeConst(case 8:/三角函数操作printf(“nt*三角函数操作(选作)*“);printf(“n“);printf(“nt注 请按要求输入其中 代表 sin !代表 cos 代表 tan “);printf(“nt 角度用弧度表示,例如1 即表示 sin 1“);printf(“nt 本操作只可求三角函数值,如需其他操作请将结果带入其它操作中“);printf(“nt 输入一个字符请按回车,确保正确录入“);prin
17、tf(“nt*“);double opr1,result1;char opr;printf(“n 请按要求输入“);scanf(“%c“,getch();scanf(“%lf“,getch();result1=Operate1(opr,opr1);printf(“结果为%f“,result1); getch();break;case 0:/*退出*/5、函数的调用关系除了主函数 main()外,其他各个函数相对于其它函数来说是独立的,函数的使用都由- - 9主函数 main()调用使用的,可以简单的说,各个函数都是主函数下的从函数。五、 【设计分析】1, 开始设计时我设想建树时可以设定五个域,
18、左右孩子,标志 tag, int 型值域,char 型值域。但是在存储时发现每个字符只需占一个域就可以,所以我又采用共同体这样节约了内存。2. 在算法设计中,构造表达式树的时候,本来以为使用递归构造表达式会很难做到出错处理的,所以采用了顺序栈辅助构造方法,并且尽可能地对程序进行完善,出错处理。但是经过与同学的相互讨论和研究,发现自己的想法犯了很大的错误,递归构造表达式对于出错处理很简单也很完善,这一点让我加深了递归的使用和理解。3.也就是三角函数问题,我最头疼的地方。首先开始运行时会出现错误,无法输出正确结果。通过网上搜索,我发现对于三角函数的定义类型必须是double,这样的话,如果要改的话
19、,差不多改大半程序,所以我就让此功能单独出来,由提示让用户手动完成。4、在调试的过程中,花费时间最为多的是对输入错误表达式的出错处理,更改增加的代码几乎都是为了出错处理,但是,觉得这样的调试才更能锻炼一个人的编程能力。六、 【调试分析】1.进入演示程序主界面2.第一次输入,需要选择 1 功能一选择1进入测试输入正确的前缀表达式操作1、输入的前缀表达式为一个不大于 9 常量:8- - 102、输入前缀表达式为一个变量:Z3、输入前缀表达式为一个简单的运算表达式:-914、输入前缀表达式为一个较为复杂的、带有变量的表达式:+*3x3*2x2x65、输入前缀表达式*-+23a+b*34 ,输出带括弧
20、的表达式6、输入错误的前缀表达式:+999和+*5x2*8x/*在按原表达式输入形式中,输入的常量保存到数组 save_number 中,常量最多为 50 个,0 单元不用*/char Expr_String50;/*存放表达式的字符串*/*以字符序列的形式输入语法正确的前缀表达式,保存到字符串 string*/*参数 flag=0 表示输出的提示信息是“请输入正确的前缀表示式:“*/*flag=1 表示输出的提示信息为“请以表达式的原书写形式输入正确表示式:“*/Status Input_Expr(char *string,int flag)- - 15if(flag=0)printf(“n
21、 请输入正确的前缀表示式:“);else printf(“n 请以表达式的原书写形式输入正确表示式:“);flushall();/*清理缓冲区*/gets(string);/*从键盘输入一串字符串作为表达式*/if(strlen(string)=1)/*输入的表达式字符串长度为 1*/if(string0=+|string0=-|string0=*|string0=/|string0=)/*输入的表达式只有一个运算符*/ printf(“n 表达式只有一个字符,为运算符,错误!“);return ERROR;else if(string0=0(*E)-data.num=stringi-48;e
22、lse if(stringi=1(*E)-data.num=save_numberstringi;else/*为变量*/(*E)-data.tag=CHAR;(*E)-data.c=stringi;/*以正确的前缀表示式并构造表达式 E*/Status ReadExpr(BiTree *E,char *exprstring)SqStack S;/定义顺序栈 Sint i,len;/*len 为表达式的长度*/BiTree p,q;(*E)=(BiTree)malloc(sizeof(BiTNode);/*申请二叉树的根结点的空间*/(*E)-lchild=NULL;- - 16(*E)-rch
23、ild=NULL;len=strlen(exprstring);/*len 赋值为表达式的长度*/if(len=1)/*表达式长度为 1 时,二叉树只有根结点*/judge_value(E,exprstring,0);/*将 exprstring0存入二叉树的结点中*/else judge_value(E,exprstring,0);/*将 exprstring0存入二叉树的结点中*/InitStack(/*初始化栈*/q=(*E);Push(/*入栈*/Push(/*入栈,根结点入栈两次是为判断先序输入的表达式是不是正确的表达式*/for(i=1;ilchild=NULL;p-rchild=
24、NULL;if(exprstringi=+|exprstringi=-|exprstringi=*|exprstringi=/|exprstringi=)/*为运算符,运算符入栈,左孩子不空,向左孩子走,否则,如果右孩子不空,向右孩子走*/if(!q-lchild) q-lchild=p;Push(q=p;else q-rchild=p;Push(q=p;else/*不是运算符,运算符出栈*/if(!q-lchild) q-lchild=p;Pop(else q-rchild=p;Pop(if(StackEmpty(S)/*栈空且 i=len,说明输入的表达式是正确的*/else /*输入的表
25、达式是错误的*/printf(“n 输入的表达式有误!“);return ERROR;- - 17/*如果两个字符是运算符,比较两个运算符的优先级,c1 比 c2 优先,返回OK,否则返回 ERROR*/Status Pri_Compare(char c1,char c2)if(c1=|c1=*|c1=-|c1=+|c1=/)else return ERROR;else if(c1=*|c1=/)/*c1 为乘法或除法运算符,则当 c2 为+或-,c1 比 c2 优先*/if(c2=|c2=*|c2=/) return ERROR;else return OK;else return ERRO
26、R;/*其余,c1 不比 c2 优先*/else return ERROR;/*c1 和 c2 不是运算符*/*用带括弧的中缀表达式输出表达式*/void WriteExpr(BiTree E)if(E)/*树不为空*/ /*先递归左子树*/if(E-lchildWriteExpr(E-lchild);printf(“)“);/*带括弧输出左子树*/else WriteExpr(E-lchild);/*否则,不带括弧输出左子树*/else WriteExpr(E-lchild);/*否则,输出左子树*/*访问输出根结点的值*/if(E-data.tag=INT)printf(“%d“,E-da
27、ta.num);else printf(“%c“,E-data.c);/*后递归右子树*/- - 18if(E-rchildWriteExpr(E-rchild);printf(“)“);/*带括弧输出右子树*/else WriteExpr(E-rchild);/*否则,不带括弧输出右子树*/else WriteExpr(E-rchild);/*否则,输出右子树*/*实现对表达式中的所有变量 V 的赋值(V=c),参数 flag 为表示是否赋值过的标志*/void Assign(BiTree *E,char V,int c,int *flag)if(*E)if(*E)-data.tag=CHA
28、R(*E)-data.num=c;*flag=1;Assign(/*递归左子树*/Assign(/*递归左子树*/*指数运算函数,底数为 x,指数为 exp*/long power(int x,int exp)long result;int i;for(i=1,result=1;idata.tag=CHAR)/*树不为空*/- - 20if(E-data.c!=*return ERROR;/*存在变量,提示信息,后返回 ERROR*/if(Check(E-lchild)/*递归左子树*/Check(E-rchild);/*递归右子树*/*对算术表达式求值*/long Value(BiTree
29、E)if(E)/*树不为空*/if(!E-lchild/*结点的左孩子和右孩子为空,为叶子结点,返回结点的值*/return Operate(Value(E-lchild),E-data.c,Value(E-rchild);/*运算求值,后根遍历的次序对表达式求值,其中参数递归调用了Value()函数求左子树的值和右子树的值*/*构造一个新的复合表达式*/void CompoundExpr(char P,BiTree *E1,BiTree E2)BiTree E;E=(BiTree)malloc(sizeof(BiTNode);/*申请一个结点存放运算符 P*/E-data.tag=CHAR;
30、E-data.c=P;/*申请到的结点值为 P*/E-lchild=(*E1);/*结点的左孩子为 E1*/E-rchild=E2;/*结点的右孩子为 E2*/(*E1)=E;/*(*E1)为根结点*/printf(“n 表达式 E 复合成功!其表达式变为:n“);WriteExpr(E);/*输出复合好的表达式*/*以表达式的原书写形式输入,表达式的原书写形式字符串 string 变为字符串 pre_expr*/*后调用 reversal_string()函数反转得到前缀表达式 pre_expr*/Status Read_Inorder_Expr(char *string,char *pre
31、_expr)- - 21int i,j,len,char_number=1;/*len 表示字符串 string 的长度,char_number 是记录数组 save_number的个数*/int number;/*保存大于 9 的常量*/char c,c1;SqStack1 S;/*栈定义*/InitStack1(/*初始栈*/Push1(/*先将字符#入栈,用来表示作为栈的最底一个元素*/len=strlen(string);/*len 为字符串 string 的长度*/c=stringlen-1;/*从字符串的最后一个字符开始向前扫描*/i=len-1;while(!StackEmpty
32、1(S)/*出栈,赋值给 c*/while(c!=)/*假如 c 不为),出栈*/*pre_expr+=c;if(!StackEmpty1(S)else printf(“n 输入的表达式有误!“);return ERROR;else if(c=)/*字符为),入栈*/Push1(else if(c=0j+,i-)/*循环扫描 string 前一个字符,求出常量后赋给 number*/number=(c1-48)*power(10,j)+number;/*number 为扫描到的常量*/c1=stringi-2;save_numberchar_number=number;/*将 number 存
33、入到数组save_number 中,下标为- - 22char_number*/*pre_expr+=char_number+;else if(c=a/*i 不小于 0,c=stringi循环下一个字符*/else /*否则,将清空栈*/while(!StackEmpty1(S)*pre_expr+=c;Pop1(/*将#出栈*/*pre_expr=0;/*字符串结束符*/if(ilchild/*常数合并运算,调用Operate()函数求值*/(*E)-data.tag=INT;(*E)-data.num=result;/*修改之前的运算符为常量*/free(*E)-lchild);/*释放左
34、孩子*/free(*E)-rchild);/*释放右孩子*/(*E)-lchild=(*E)-rchild=NULL;/*左右孩子置空*/else MergeConst(/*递归左孩子*/MergeConst(/*递归右孩子*/判断是否操作符 int isoperator(char c) - - 24 switch(c) case +: return TRUE;case -: return TRUE;case *: return TRUE;case /: return TRUE; case : return TRUE; default: return FALSE; void Diff(BiTr
35、ee (*E)-rchild-rchild-data.num=(*E)-rchild-rchild-data.num-1; /第二种只带单次方/第三种只为常数*/ int d,flag3;/ printf(“%c“,v);if(E-lchild)E-lchild-data.tag=INT;E-rchild-rchild-data.num=E-rchild-rchild-data.num-1;if(E-rchild-data.tag=INTE-rchild-data.tag=INT;- - 25if(E-rchild-data.c=v)E-rchild-data.tag=INT;/ Diff(E
36、-lchild,v);/ Diff(E-rchild,v);if(E-rchild-data.c=v)E-data.tag=INT;free(E-lchild);free(E-rchild);E-lchild=E-rchild=NULL; elseDiff(E-lchild,v);Diff(E-rchild,v);/ else/ / printf(“表达式不需要求偏导n“);/ /*主菜单*/char menu()char choice;printf(“nt*“);printf(“nt*9.表达式类型的实现*“);printf(“nt 1 输入正确的前缀表达式“);printf(“nt 2 带
37、括弧的中缀表示式输出“);printf(“nt 3 对变量进行赋值“);printf(“nt 4 对算数表达式求值“);printf(“nt 5 构造一个新的复合表达式“);printf(“nt 6 以表达式的原书写形式输入(选作)“);printf(“nt 7 合并表达式中所有常数运算(选作)“);printf(“nt 8 三角函数操作 (选作)“);- - 26/ printf(“nt 9 求偏导数 (选作)“);printf(“nt 0 退出“);printf(“nt*“);printf(“nt 请输入你的选择(数字)“);choice=getche();return choice;/*
38、主函数*/void main()BiTree E,E1;/*两个表达式 E 和 E1*/int flag=0;/*表达式 E 构造标志,为 0 表示未构造,为 1 表示已构造*/long result;/*保存算数表达式运算结果*/char V,P;/V 被赋值,P 为符合表达式运算符int c;/C 要赋值char string30;/字符串while(1) system(“cls“);/清屏switch(menu()case 1:/*1 输入正确的前缀表达式*/printf(“nt*输入提示信息*“);printf(“nt 输入正确的前缀表达式的要求:“);printf(“ntt【变量】
39、a-z 或 A-Z“);printf(“ntt【常量】 0-9,不能超过 9“);printf(“ntt【运算符】 +,-,*,/,(乘幂)“);printf(“ntt 例 0;5;+a*53“);printf(“nt 请输入正确的前缀表达式,后按回车键存入缓冲区,否则可能会出错!“);printf(“nt*“);if(Input_Expr(Expr_String,0)/在 flag=0 时,初始输入if(ReadExpr(printf(“n 表达式构造成功!n 输入的带括弧的中缀表达式:“);WriteExpr(E);/*带括弧的中缀表示式输出 ,递归实现*/getch();- - 27br
40、eak;case 2:/*2 带括弧的中缀表示式输出*/printf(“nt*输出说明信息*“);printf(“nt 输出带括弧的中缀表达式:“);printf(“nt【1】如果表达式已经构造成功的,输出表达式;“);printf(“nt【2】如果表达式还未构造成功的,请返回主菜单选择构造表达式;“);printf(“nt【注】其中要注意的是,可能有一些表达式构造时没有办法判断为有误,“);printf(“nt 如果输出不是你想得到的,说明你之前输入的表达式有误,请重新构造!“);printf(“nt*“);if(flag=1)printf(“n 带括弧的中缀表达式为:“);WriteExp
41、r(E);else printf(“n 表达式未构造成功!请重新构造成功的表达式!“);getch();break;case 3:/*3 对变量进行赋值*/printf(“nt*赋值操作说明信息*“);printf(“nt 赋值操作:实现对表达式中的某一个变量 V的赋值,即使 V=C,C 为一整数“);printf(“nt 【1】根据输出的表达式,输入要赋值的变量 V,只能输入一个字符,否则出错“);printf(“nt 【2】输入要将变量 V 赋值为的整数 C,只能是整数,否则出错“);printf(“nt 【注】如果表达式未构造,请回到主菜单选择构造表达式“);printf(“nt*“);
42、if(flag=1)int Assign_flag=0;printf(“n 表达式 E 为:“);WriteExpr(E);flushall();/*清理缓冲区*/- - 28printf(“n 请输入要赋值的字符:“);V=getchar();printf(“请输入要将赋值为:“);scanf(“%d“,Assign(/赋值并改变标志if(Assign_flag)printf(“n 赋值成功!n 赋值后的表达式为:“);WriteExpr(E);else printf(“n 表达式里没有%c 这个变量!“,V);else printf(“n 表达式未构造成功!请构造成功的表达式!“);get
43、ch();break;case 4:/*4 对算数表达式求值*/printf(“nt*算数表达式求值说明信息*“);printf(“nt 【注】如果表达式还有变量未赋值,即表达式不是算数表达式“);printf(“nt 不能求出表达式的值,请回到主菜单选择赋值操作,后再求值“);printf(“nt*“);if(flag=1)printf(“n 算数表达式:“);WriteExpr(E);if(Check(E) /检查是否全赋值result=Value(E);printf(“n 求算数表达式的值:t“);WriteExpr(E);printf(“=%ld“,result);else print
44、f(“n 表达式未构造成功!请构造成功的表达式!“);getch();break;case 5:/*5 构造一个新的复合表达式*/printf(“nt*构造新的复合表达式说明信息*“);printf(“nt 【1】构造一个新的表达式 E1,采用表达式的原书写形式输入“);printf(“nt 【2】构造表达式 E1 成功后,输入要复合表达式 E 和 E1 的操作运算符(+,-,*,/,)“);printf(“nt 【注】如表达式 E 未构造,不能复合表达式;如构造表达式 E1 错误,复合失败“);- - 29printf(“nt*“);if(flag=1)printf(“n 表达式 E1 为:“);WriteExpr(E);printf(“n 请构造新的表达式 E2:“);flushall();/*清理缓冲区*/if(Input_Expr(string,1)/标志为 1,输入字符串if(Read_Inorder_Expr(string,Expr_String)/入栈reversal_string(Expr_String);/反转if(ReadExpr(printf(“n 表达式 E1 构造成功!“);WriteExpr