当前位置:文档之家› (完整版)数学表达式计算(c语言实现)

(完整版)数学表达式计算(c语言实现)

一、设计思想计算算术表达式可以用两种方法实现:1.中缀转后缀算法此算法分两步实现:先将算术表达式转换为后缀表达式,然后对后缀表达式进行计算。

具体实现方法如下:(1)中缀转后缀需要建一个操作符栈op和一个字符数组exp,op栈存放操作符,字符数组用来存放转换以后的后缀表达式。

首先,得到用户输入的中缀表达式,将其存入str数组中。

对str数组逐个扫描,如果是数字或小数点,则直接存入exp数组中,当扫描完数值后,在后面加一个#作为分隔符。

如果是操作符,并且栈为空直接入栈,如果栈不为空,与栈顶操作符比较优先等级,若比栈顶优先级高,入栈;如果比栈顶优先级低或相等,出栈将其操作符存到exp数组中,直到栈顶元素优先等级低于扫描的操作符,则此操作符入栈;如果是左括号,直接入栈,如果是右括号,出栈存入exp数组,直到遇到左括号,左括号丢掉。

然后继续扫描下一个字符,直到遇到str中的结束符号\0,扫描结束。

结束后看op栈是否为空,若不为空,继续出栈存入exp数组中,直到栈为空。

到此在exp数组最后加结束字符\0。

我们就得到了后缀表达式。

(2)后缀表达式计算此时需要一个数值栈od来存放数值。

对exp数组进行逐个扫描,当遇到数字或小数点时,截取数值子串将其转换成double类型的小数,存入od栈中。

当遇到操作符,从栈中取出两个数,进行计算后再放入栈中。

继续扫描,知道扫描结束,此时值栈中的数值就是计算的结果,取出返回计算结果。

2.两个栈实现算法此算法需要两个栈,一个值栈od,一个操作符栈op。

将用户输入的数学表达式存入str数组中,对其数组进行逐个扫描。

当遇到数字或小数点,截取数值子串,将其转换成double类型的数值存入od栈中;当遇到左括号,直接入op栈;遇到右括号,op栈出栈,再从值栈od中取出两个数值,计算将其结果存入值栈中,一直进行此操作,直到操作符栈栈顶为左括号,将左括号丢掉。

如果遇到操作符,若op栈为空,直接入栈;若栈不为空,与栈顶元素比较优先等级,若比栈顶操作符优先等级高,直接入op栈,如果低于或等于栈顶优先等级,op栈出栈,再从值栈中取出两个数值,计算将其结果存入值栈中,一直进行此操作,直到栈顶优先等级低于扫描的操作符等级,将此操作符入op栈。

继续扫描直到遇到str中的结束字符\0,扫描结束。

此时看操作符栈是否为空,若不为空,出栈,再从值栈中取出两个数值进行计算,将其结果存入值栈,一直进行此操作,直到操作符栈为空。

此时把值栈中的数值取出,即为所得的最终计算结果。

二、算法流程图第一种算法:中缀转后缀算法其主函数流程图为:返回计算结果图1 主函数算法流程图中缀转后缀算法流程图如下:放入exp数组中图2 中缀转后缀算法流程图计算后缀表达式流程图如下:图3 后缀表达式计算流程图第二种算法:两个栈算法其主函数流程图为:返回计算结果图4 主函数算法流程图直接计算数学表达式流程图如下:图5 直接计算表达式流程图三、源代码下面给出的是用中缀转后缀算法实现的程序的源代码:#include<stdio.h>#include<string.h>#include<math.h>#include<stdlib.h>#define MAXSIZE 100 //定义宏,数组最大长度为100//函数实现中缀转后缀,将存储数学表达式的数组str传参进来,exp存储后缀表达式void trans(char str[],char exp[]){struct{char data[MAXSIZE];//用来存放操作符int top;//数组下标}op;//用结构体创建操作符栈char ch;int i=0,j=0,tempi=0;op.top=-1;//给操作符栈初始化,令下标为-1while(ch!='\0'){ch=str[i]; //取str数组的第i个元素赋值给chif((ch>='0'&& ch<='9') || ch=='.')//对数值操作{tempi=i;//若ch为数字或小数点,将其下标值赋给临时下标tempi//依次向后扫描str数组,若一直为数字,跳入while循环while((ch>='0' && ch<= '9') || ch == '.'){tempi++;exp[j]=ch;//将数字存入exp数组中j++;ch=str[tempi];//取str数组中下标为tempi的元素赋给ch}exp[j]='#';j++;//用#做分隔符,将数值分隔开i=tempi;//跳出循环,将此时的tempi赋给i,继续向后扫描}//对操作符操作else if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='%' || ch == '(' || ch == ')'){int level(char op);//声明level函数if(ch=='(')//如果为(,直接进栈{op.top++;op.data[op.top]=ch;//进栈操作}else if(ch==')'){//如果为),一直出栈直到遇到(while(level(op.data[op.top])!=-1)//若栈顶元素不为(,进入while循环{exp[j]=op.data[op.top];//操作符出栈,存入exp数组中op.top--;j++;if(op.top==-1)break;//如果栈为空,跳出循环}op.top--;//左括号pop出来}else if(op.top==-1)//如果栈为空,直接进栈{op.top++;op.data[op.top]=ch;//进栈操作}//如果所扫描的操作符优先等级比栈顶元素高,直接进栈else if(level(ch)>level(op.data[op.top])){op.top++;op.data[op.top]=ch;//进栈操作}else{//如果所扫描的操作符优先等级没有栈顶元素高,//一直出栈直到比栈顶元素优先级高while(level(ch)<=level(op.data[op.top])){exp[j]=op.data[op.top];//出栈存入exp数组中op.top--;j++;if(op.top==-1)break;//如果栈为空,跳出循环}op.top++;op.data[op.top]=ch;//比栈顶元素优先级高,入栈}i++;//str下标加1,向后扫描}}while(op.top!=-1)//扫描结束后如果操作符栈不为空,出栈直至为空{exp[j]=op.data[op.top];//出栈存入exp数组中op.top--;j++;}exp[j]='\0';//赋\0结束exp字符数组}int level(char op)//判断操作符优先等级{if(op == '+' || op == '-')//若为+、-,等级为1return 1;else if(op == '*' || op == '/' || op == '%')return 2; //若为*、/、%,等级为2else if(op == '(')return -1 ; //若为(,等级为-1elsereturn -3; //其他等级为-3;}double calvalue(double od1,double od2,char tempop)//计算{switch(tempop){case '+':return od1 + od2; //计算加法case '-':return od1 - od2;//计算减法case '*':return od1 * od2;//计算乘法case '/':return od1 / od2;//计算除法case '%':return fmod(od1,od2);//求余}return 0;}double calculate(char exp[])//计算后缀表达式{struct //用结构体创建值栈{double data[MAXSIZE]; //存储数值int top;}od;double d; //声明d变量存储数值double od1,od2; //存储值栈依次pop出来的操作数char ch;char tempch[20]; //声明临时数组存储子串int j=0,t;int length=strlen(exp);//计算exp数组的长度od.top=-1; //初始化值栈,令下标为-1while(j<length){ch=exp[j];//提取exp中第j个元素if(ch!='+' && ch!='-' && ch!= '*' && ch!='/' && ch!='%'){//如果为数字或小数点t=0;while((ch>='0' && ch<='9') ||ch=='.'){tempch[t]=ch;t++;//依次存放到临时数组中j++;ch=exp[j];}tempch[t]='\0';//结束tempch数组d=atof(tempch);//将子串转化成double类型的数od.top++;od.data[od.top]=d;//入值栈}else //若为操作符,从值栈中pop出两个数计算{od2=od.data[od.top];od.top--;//先出栈的赋给od2od1=od.data[od.top]; //后出栈的赋给od1od.data[od.top]=calvalue(od1,od2,ch); //计算出结果后再入栈}j++;}return od.data[od.top];//将结束后值栈中的数pop出来,即为计算结果}main(){char str[MAXSIZE],exps[MAXSIZE]; //定义两个数组printf("请输入算术表达式:\n");gets(str); //从控制台输入算数表达式printf("表达式为:%s\n",str);trans(str,exps); //调用trans函数,得到后缀表达式printf("后缀表达式:%s\n",exps);printf("结果为:%lf\n", calculate(exps)); //调用calculate函数,计算结果}下面给出的是用两个栈算法实现的程序的源代码:#include<stdio.h>#include<string.h>#include<math.h>#include<stdlib.h>#define MAXSIZE 100 //定义宏,数组最大长度为100double calculate(char str[]){struct //用结构体创建操作符栈{char data[MAXSIZE];//用来存放操作符}op;struct //用结构体创建值栈{double data[MAXSIZE];//用来存放操作数int top;}od;char ch;char tempch[20];//声明临时数组存储子串int j=0,t;double d;double od1,od2;//存储值栈依次pop出来的操作数char tempop;int length=strlen(str);//计算str数组的长度op.top=-1;//初始化操作符栈,令下标为-1od.top=-1;//初始化值栈while(j<length){ch=str[j];if((ch>='0' && ch<='9') ||ch=='.')//若为数值或小数点{d=0;t=0;while((ch>='0' && ch<='9') ||ch=='.')//截取子串{tempch[t]=ch;t++;//赋值给临时数组j++;ch=str[j];}tempch[t]='\0';d=atof(tempch);//将子串转化成double类型的数od.top++;od.data[od.top]=d;//入值栈}//对操作符操作else if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='%' || ch == '(' || ch == ')') {if(ch=='(')//如果为(,直接进栈{op.top++;op.data[op.top]=ch;//进栈操作}else if(ch==')')//如果为),一直出栈直到遇到({int level(char op);//声明level函数while(level(op.data[op.top])!=-1)//若栈顶元素不为(,进入while循环{//声明calvalue函数double calvalue(double od1,double od2,char tempop);od2=od.data[od.top];od.top--;od1=od.data[od.top];tempop=op.data[op.top];op.top--;od.data[od.top]=calvalue(od1,od2,tempop);//计算出结果后入值栈if(op.top==-1)break;//如果操作符栈为空,跳出循环}op.top--;//左括号pop出来}else if(op.top==-1)//如果栈为空,直接进栈{op.top++;op.data[op.top]=ch;//进栈操作}//如果所扫描的操作符优先等级比栈顶元素高,直接进栈else if(level(ch)>level(op.data[op.top])){op.top++;op.data[op.top]=ch;//进栈操作}else{//如果所扫描的操作符优先等级没有栈顶元素高,//一直出栈直到比栈顶元素优先级高while(level(ch)<=level(op.data[op.top])){od2=od.data[od.top];od.top--;od1=od.data[od.top];tempop=op.data[op.top];op.top--;od.data[od.top]=calvalue(od1,od2,tempop);//计算结果后入值栈if(op.top==-1)break;//如果栈为空,跳出循环}op.top++;op.data[op.top]=ch;//比栈顶元素优先级高,入操作符栈}j++;//str下标加1,向后扫描}}while(op.top!=-1)//扫描结束后如果操作符栈不为空,出栈直至为空{od2=od.data[od.top];od.top--;od1=od.data[od.top];tempop=op.data[op.top];op.top--;od.data[od.top]=calvalue(od1,od2,tempop);//计算结果后入值栈}return od.data[od.top];//将结束后值栈中的数pop出来,即为计算结果}int level(char op)//判断操作符优先等级{if(op == '+' || op == '-')//若为+、-,等级为1return 1;else if(op == '*' || op == '/' || op == '%')return 2; //若为*、/、%,等级为2else if(op == '(')return -1 ; //若为(,等级为-1elsereturn -3; //其他等级为-3;}double calvalue(double od1,double od2,char tempop)//计算{switch(tempop){case '+':return od1 + od2;//计算加法case '-':return od1 - od2;//计算减法case '*':return od1 * od2;//计算乘法case '/':return od1 / od2;//计算除法case '%':return fmod(od1,od2);//求余}return 0;}void main(){char str[MAXSIZE];//定义str数组存放数学表达式printf("输入算术表达式:\n");gets(str); //从控制台输入算数表达式printf("结果是:%lf\n",calculate(str));//调用calculate函数,计算结果}四、运行结果图6 中缀转后缀算法运行结果图7 两个栈算法运行结果五、遇到的问题及解决编程的前期工作很重要,需要明确的理清思路,而编写运行的过程中更是会出现很多问题,有因粗心造成的拼写错误,有语法错误,也有逻辑错误。

相关主题