《计算机软件技术实习》之简单计算器的实现
作者:互联网
《计算机软件技术实习》之简单计算器的实现
实验要求:
- 学习图形界面的设计,利用 MFC 应用程序(Java swing 或 QT 框架,或 C#)创建基于对话框的应用程序,添加按钮、编辑框等控件;
- 能通过设计的按钮控件输入并实现简单算术运算,要求表达式在编辑框中显示,能将运算结果,输出在编辑框内显示;并保存历史的表达式运算记录。
- 也能够实现混合运算的算术表达式求解,算术表达式中包括加、减、乘、除、括号等运算符;并且能够识别括号,优先级正确。
实验准备:
1.1算术表达式求值 :参与运算的数据(即操作数)可以为整数或实数,运算符(即操作符)为+、-、、/(加、减、乘、除)等二元操作符,包括圆括号;
如 :56+10-25=15
6+(5-4/2)*3=15
运算规则:
先乘除,后加减,从左到右计算,先括号内,后括号外;
表达式的三种表示法特点:
1)操作数之间的相对次序不变;
2)运算符的相对次序不同;
3)后缀表达式中已考虑了运算符的优先级,没有括号,只有操作数和运算符。
这一次我所运用到的方法是:方法二:双栈算符优先级法。
双栈算符优先级法为了实现表达式求值,需要设置两个栈:
一个是运算符栈OP,用于寄存运算符;
另一个成为操作数栈OPND用于寄存运算数和运算结果。
算法的关键是判断运算符的优先级。
如果操作符的优先级比较高就直接入OP栈,如果优先级较低的话,需要先将OPND栈顶的两个操作数提取出来进行运算,然后将结果再一次入栈。遇到右括号需要运算,弹出OP栈直到左括号的所有操作数,然后将结果存到栈中。
核心思想就是这样,具体算法如下所示:(大部分C++语言我已经将核心思想注释过了)
比较优先级函数:
int priority(int state, char a){
int rank;
switch (a) {
case '+':
case '-':
rank = 1;//+,-优先级为1。
break;
case '*':
case '/':
rank = 2;//*,/优先级为2。
break;
case '(':// 保证“(”直接入栈 ,也不会干扰其他运算符判断。
if (state == 0)
rank = 3;
else
rank = 0;
break;
case '#':
rank = 0;//#表示结束。
break;
default:
break;
}
return rank;
}//priority函数主要来判断栈里面运算符的优先级。
计算表达式函数:
double calculate(char op, double num1, double num2)
{
double anwser;
switch (op) {
case '+':
anwser = num1 + num2;
break;
case '-':
anwser = num1 - num2;
break;
case '*':
anwser = num1 * num2;
break;
case '/':
anwser = num1 / num2;
break;
default:
break;
}
return anwser;
}//calculate函数主要是实现两个数字的运算(包括加减乘除),以op来读取OP栈里面的运算符。
读入表达式并且计算的出结果的函数:
```cpp
```cpp
double result(string s,int a,int &sign) {
stack<char> OP;//定义OP栈来存放操作运算符。
stack<double> OPND;//定义OPND来存放需要运算的数字(包括小数)。
OP.push('#');//先在运算符的栈之中放入一个中止运算符。
OPND.push(0);
string num;//用来保存一个完整的运算数字。
for (int i = 0; i<a; i++) {//读取整个s字符串。
if ((s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/') && (s[i + 1] == '+' || s[i + 1] == '-' || s[i + 1] == '*' || s[i + 1] == '/'))
{
sign = 0;
break;
}
if (s[i] == '/' && s[i + 1] == '0')
{
sign = 0;
}
if (isdigit(s[i])) {//判断是否为0到9的数字。
while (isdigit(s[i]) || s[i] == '.') {
num.push_back(s[i]);//判断输入小数点之后,在末尾增加一个小数点。
i++;//继续后移一位,读入小数点后面的部分。
}
double a = atof(num.c_str());//把上面读取出来的整个数字字符串转化为双精度类型的数字赋值给a。
OPND.push(a);// 将a这个数字放入OPND的栈之中。
num.clear();//清除num中的数字。
i--;//后移一位。
}
else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '(') {
if (s[i] == '(') {
if (s[i + 1] == '-')
OPND.push(0);
};
if (priority(0, s[i]) > priority(1, OP.top()))//比较字符串s中的运算符优先级和OP栈中的优先级,大则入栈。
OP.push(s[i]);
else {
while (priority(0, s[i]) <= priority(1, OP.top())) {
char temp = OP.top();//定义temp保存OP栈顶运算符。
OP.pop();//弹出栈顶
double op2 = OPND.top();//将OPND栈顶的数字赋值给op2(由于先进后出原则,必须赋值给op2保证运算顺序)。
OPND.pop();//弹出栈顶
double op1 = OPND.top();//取出OPND当前栈顶的数字,进行下一步的运算。
OPND.pop(); //弹出栈顶
OPND.push(calculate(temp, op1, op2));//将计算结果入栈。
}
OP.push(s[i]);
}
}
else if (s[i] == ')') {
while (OP.top() != '(') {//取出操作,直到将取出OP栈中的“(”为止。
char temp = OP.top();
OP.pop();
double op2 = OPND.top();
OPND.pop();
double op1 = OPND.top();
OPND.pop();
OPND.push(calculate(temp, op1, op2));
}
OP.pop();//弹出“)” ,结束。
}//上面的操作已经判断过优先级,所以括号里的数字可以直接计算,无需重复判断。
}
while (OP.top() != '#') {
char temp = OP.top();
OP.pop();
double op2 = OPND.top();
OPND.pop();
double op1 = OPND.top();
OPND.pop();
OPND.push(calculate(temp, op1, op2));
}//将栈中的运算符全部取出来,计算完成全部表达式,将值再一次放回OPND栈中。
return OPND.top();
;//此时结果OPND栈顶的结果就是整个表达式的结果。
}
`
需要判断是否符合表达式的规范,并且要让输出的结果有小数输出double类型,没有小数输出int类型。所以我设置了一个sign标识符来便于识别整个表达式是否符合标准,如果sign为1;说明符合可以输出,sign为0的话说明输入表达式有误。具体实现如下所示:
int main(){
double b;
string s;
int a,SIGN=1;//标志位首先置为1
cin>>s;
a=s.length();
b=result(s,a,SIGN);
if(SIGN==1)
cout<<b<<endl;
if(SIGN==0)//判断条件不符合正确表达式会把标志置为0.
cout<<"Error!Please enter the correct expression."<<endl;
}
这是C++的完整实现,我会在下一篇blog之中将讲述基于MFC的C++代码具体学习以及实现。
我所参考的资料为:CSDN上的yujunseu原创博客。链接如下:https://blog.csdn.net/yj3254/article/details/43705713?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control
标签:计算机软件,double,top,OPND,运算符,计算器,实习,优先级,OP 来源: https://blog.csdn.net/qq_48063427/article/details/110651942