1、问题描述
对于给定的一个表达式,表达式中可以包括常数、算术运行符(包括:“+”、 “-”、“*”、“/”、“%”(求余运算)、“^”(乘幂运算)、“!”(阶乘运算))和括 号,编写一个简单计算器,实现表达式的计算。
基本要求:从键盘输入一个正确的表达式,将表达式转换为对应的后缀表达式,并计算后缀 表达式的值。对于表达式中的简单错误(如,除数不能为零、负数无法求阶乘等),能够给出提 示,并给出错误信息;表达式中可以包括单个字母表示的变量。
提高要求:完成基本要求的基础上,能够支持一部分不规范的表达式(如,3-3+-6),支持 科学计数法表示的数(如,19971400000000 表示为:1.99714E13),并具有图形用户界面的简单计算器
2.需求分析
软件的基本功能:由键盘输入中缀表达式,程序可以将输入的中缀表达式转换成对应的后缀表达式,并计算后缀表达式的值。对于在输入时发生的简单错误,程序可以给出提示。本程序支持含负数、小数、多位数等多种操作数的处理,可以计算含加、减、乘、除、求余、求幂等多种运算符的表达式,并能判断表达式括号是否匹配。
输入/输出形式:用户可以通过控制台,根据输入提示。
输入形式:
①正确的不含字母变量的中缀表达式;
②含有简单错误的中缀表达式。
输出形式:
①对于正确的中缀表达式,可以输出其转化后的后缀表达式及表达式的计算结果;
②对于含有简单错误的中缀表达式,程序将自动输出错误提示,并给出错误信息。
测试数据要求:用户可以输入一个符合要求的中缀表达式,也可以输入一个包含简单错误的表达式。表达式中可以包括各种类型的常数以及负数等,操作符包括(+、-、*、/、%、^)等,同时表达式还可以包括各种括号。
3.所要利用的数据结构:栈
ADT SeqStack
Data
栈中元素具有相同类型及后进先出特性,相邻元素具有前驱和后继关系
Operation
SeqStack
前置条件:栈不存在
输入:无
功能:栈的初始化
输出:无
后置条件:构造一个空栈
~ SeqStack
前置条件:栈已存在
输入:无
功能:销毁栈
输出:无
后置条件:释放栈所占用的存储空间
Push
前置条件:栈已存在
输入:元素值x
功能:在栈顶插入一个元素x
输出:如果插入不成功,抛出异常
后置条件:如果插入成功,栈顶增加了一个元素
Pop
前置条件:栈已存在
输入:无
功能:删除栈顶元素
输出:如果删除成功,返回被删元素值,否则,抛出异常
后置条件:如果删除成功,栈顶减少了一个元素
GetTop
前置条件:栈已存在
输入:无
功能:读取当前的栈顶元素
输出:若栈不空,返回当前的栈顶元素值
后置条件:栈不变
Empty
前置条件:栈已存在
输入:无
功能:判断栈是否为空
输出:如果栈为空,返回1;否则,返回0
后置条件:栈不变
End ADT
#include <stdio.h> #include <iostream> #include <stdlib.h> #include <string.h> #include <windows.h> #include <math.h> #define pi 3.1415926 using namespace std; /***************************************************************************************************************************************/ /***函数定义部分***/ void adorn(char adorn,int n);//装饰函数 int fun(char *c1, int s, int e);//判断括号是否匹配 void PrintList(int top,float a[]);//打印计算结果 char input();//从键盘中读取数据 char Change(char c1[]); //将中缀表达式转换为后缀表达式并进行计算 int main();//使系统可以在函数内调用main函数 /***************************************************************************************************************************************/ /***************************************************************************************************************************************/ /***定义三个字符串,以便实现栈操作 ***/ char c1[1024];//用于存储输入的中缀表达式 char c2[1024];//为栈用于转化过程中对数和操作符进行压栈 char c3[1024];//用于元素出栈后进行相关运算,并将最终结果进行重新压栈 /***************************************************************************************************************************************/ /***************************************************************************************************************************************/ /***定义全局变量***/ float a[1024];// 用于最后计算结果的输出使用 int count=0; /***************************************************************************************************************************************/ /***************************************************************************************************************************************/ /***各子函数实现部分***/ void adorn(char adorn,int n)//装饰函数 { for(int i=0;i<n;i++) { putchar(adorn);//通过ASCLL码判断如果是数字则将ASCLL码-48转换为字符 } putchar('\n'); //强制在字符串的结尾加上\n,方便计算字符串内的个数 } int fun(char *c1, int s, int e)//判断括号是否匹配 (1匹配;0不匹配) { char L; char R; while((s<=e)) { switch(c1[s]) { case '(': L = c1[s]; R = ')'; break; case '[': L = c1[s]; R = ']'; break; case '{': L = c1[s]; R = '}'; break; case ')': return 0; case ']': return 0; case '}': return 0;//若输入字符串为以上字符,则返回0 default: L = '\0'; break; } if(c1[s] == L) { int p = 1; int q=0; int x = s+1;//t为s的下一个字符 while((x<=e)) // 搜索匹配的右括号 { if(c1[x] == L) p++; if(c1[x] == R) q++; if(q>p) return 0; if(p == q) // 再对已匹配括号里面的括号进行匹配 { if(fun(c1, s+1, x-1) == 0) // 递归调用,从最外层的括号分别向内匹配 return 0; s=x; break; } x++; } if(p>q) return 0; } s++; } return 1;//都匹配上返回1 } void PrintList(int top,float a[])//打印计算结果 { cout<<"计算结果为:"<<endl; if(a[top]>1000||a[top]<0.001) //科学计数法 printf("%.3E\n",a[top]); else if(a[top]<=1000||a[top]>=0.001) printf("%.8f\n",a[top]); adorn('-',90); } char input()//从键盘中读取数据 { int count=0; int i; int j; int m; int n; int top=0; int v=-1; int u=0; fflush(stdin); gets(c1);//输入c1 } char Change(char c1[])//将中缀表达式转换为后缀表达式并进行计算 { fflush(stdin); int count=0; int i; int j; int m; int n; int top=0; int v=-1; int u=0; int k=strlen(c1); int r= fun(c1, 0, k-1); if(r != 1) { printf("**括号不匹配,请重新输入**:\n"); loop: input(); if(*c1=='#') { main();//返回主函数 } else { Change(c1); } } else { for(i=0;i<k;i++)//对输入的数组进行后缀表达式转换 { switch(c1[i]) { case '(': c2[++top]=c1[i]; break; case '+': case '-': while(top>0 && c2[top]!='(')//判断栈顶的元素是否为括号,且栈不空时 ,将栈中的前两个元素进行出栈与运算,将运算的结果进行重新入栈 { c3[++v]=c2[top]; c3[++v]=' '; top--; } c2[++top]=c1[i]; //当栈空或者遇到(时,将"-"直接入栈 break; case '*': case '/': while(top>0 && c2[top]!='(' && c2[top]!='+' && c2[top]!='-')//考虑优先级 { c3[++v]=c2[top]; c3[++v]=' '; top--; } c2[++top]=c1[i]; break; case '%': while(top>0 && c2[top]!='(' && c2[top]!='+' && c2[top]!='-')//考虑优先级 { c3[++v]=c2[top]; c3[++v]=' '; top--; } c2[++top]=c1[i]; break; case '^': while(top>0 && c2[top]!='(' && c2[top]!='+' && c2[top]!='-')//考虑优先级 { c3[++v]=c2[top]; c3[++v]=' '; top--; } c2[++top]=c1[i]; break; case '!': while(top>0 && c2[top]!='(' && c2[top]!='+' && c2[top]!='-')//考虑优先级 { c3[++v]=c2[top]; c3[++v]=' '; top--; } c2[++top]=c1[i]; break; case ')': while(c2[top]!='('){ c3[++v]=c2[top]; c3[++v]=' '; top--; } top--; break; default: c3[++v]=c1[i]; if(c1[i+1]>'9' || c1[i+1]<'0') c3[++v]=' '; break; } } while(top>0 && c2[top]!='(') { c3[++v]=c2[top]; c3[++v]=' '; top--; } cout<<"其后缀表达式为:"<<endl; puts(c3); top=0; float sum; k=strlen(c3); for(i=0;i<k;i++) { if(c3[i]==' ') { ; } else if(c3[i]=='+') { sum=a[top-1]+a[top]; a[--top]=sum; } else if(c3[i]=='-') { sum=a[top-1]-a[top]; a[--top]=sum; } else if(c3[i]=='*') { sum=a[top-1]*a[top]; a[--top]=sum; } else if(c3[i]=='/') { if(a[top]==0) { cout<<"**输入错误,被除数不能为0,请重新输入**:"<<endl; goto loop; } else { sum=a[top-1]/a[top]; a[--top]=sum; } } else if(c3[i]=='%') { if(a[top]==0) { cout<<"**输入错误,被取余数不能为0,请重新输入**:"<<endl; goto loop; } else { int sum1=a[top-1]*10; int sum2=a[top]*10; sum=(sum1%sum2)/10; a[--top]=sum; } } else if(c3[i]=='^') { sum=pow(a[top-1],a[top]); a[--top]=sum; } else if(c3[i]=='!') { if(a[top]<0) { cout<<"**输入错误,负数没有阶乘,请重新输入**:"<<endl;//提示信息,并重新输入 input(); goto loop; } else { float sum=1; for(int j=1;j<=a[top];j++) { sum=sum*j; } a[top]=sum; } } else { int m=0; while(c3[i]>='0' && c3[i]<='9') { m=10*m+c3[i]-'0'; i++; } a[++top]=m; } } PrintList(top,a); } } /***************************************************************************************************************************************/ /***************************************************************************************************************************************/ /***主函数部分***/ int main() { system("cls");//实现启动器的DOS功能,清除显示器屏幕上的内容,使DOS提示符到屏幕左上角 while(1) { fflush(stdin);//清除缓冲区的值 int count=0; int i; int j; int m; int n; int top=0; int v=-1; int u=0; adorn('-',90); cout<<"**请输入需要计算的中缀表达式,直接回车即可,注意本系统只识别英文符号**:" <<endl; cout<<"如果想退出本界面,请输入‘#’号键"<<endl; input(); if(*c1=='#') { break; } else { Change(c1); } } } /***************************************************************************************************************************************/