您的位置:首页 > 其它

简单计算器,四则运算,小括号,实数,剔除空格,封装calculator类

2017-02-18 21:01 666 查看

简单表达式的求值,在《数据结构》教课书上有明确的阐述。

先处理只涉及四则运算的情况。

再添加小括号的情况。

然后处理表达式中包含实数的情况。

最后处理表达式中包含空格的情况。

 

一、对于只涉及加减乘除的表达式.

1设立两个栈,运算符栈和数字栈。

2遍历表达式,解析出里面的数字和运算符。

3数字部分直接压栈,运算符部分视优先级情况而定。

4遍历完毕,数字栈中剩余的那一个数字时,为运算结果。

 

只涉及四则运算的使用,数字全为整数。

 

代码的主要逻辑在main函数中。

ch2num函数完成运算符到数字的映射。

规则为:‘#’---0,‘+’---1,‘-’---2,‘*’---3,‘/’---4。

compare二维数组记录运算符之间的优先级。

compare[i][j]=1,表示i比j优先级高;compare[i][j]=0,表示i的优先级不高于j。
operator_2

函数完成四则运算。简单表达式的求值,在《数据结构》教课书上有明确的阐述。

先处理只涉及四则运算的情况。

再添加小括号的情况。

然后处理表达式中包含实数的情况。

最后处理表达式中包含空格的情况。

对于只涉及加减乘除的表达式,

1设立两个栈,运算符栈和数字栈。

2遍历表达式,解析出里面的数字和运算符。

3数字部分直接压栈,运算符部分视优先级情况而定。

4遍历完毕,数字栈中剩余的那一个数字时,为运算结果。

只涉及四则运算的使用,数字全为整数。

代码的主要逻辑在main函数中。

ch2num函数完成运算符到数字的映射。

规则为:‘#’---0,‘+’---1,‘-’---2,‘*’---3,‘/’---4。

compare二维数组记录运算符之间的优先级。

compare[i][j]=1,表示i比j优先级高;compare[i][j]=0,表示i的优先级不高于j。

operator_2函数完成四则运算。

#include<stdio.h>
#include<stack>
#include<string.h>
using std::stack;

int ch2num(char ch) {
int num(-1);
switch (ch) {
case '#':num = 0; break;
case '+':num = 1; break;
case '-':num = 2; break;
case '*':num = 3; break;
case '/':num = 4; break;
}//switch
return num;
}//ch2num
double operator_2(double num1, double num2, char ch) {
double num(0.0);
switch (ch) {
case '+':num = num2 + num1; break;
case '-':num = num2 - num1; break;
case '*':num = num2*num1; break;
case '/':num = num2 / num1; break;
}//switch
return num;
}//operator_2
int compare[5][5] = { { 0 },{ 1 },{ 1 },{ 1,1,1 },{ 1,1,1 } };

int main() {
freopen("in.txt", "r", stdin);
char str[250];
stack<double> S_num;
stack<char> S_ch;
while (gets_s(str)) {
while (!S_ch.empty())S_ch.pop();
S_ch.push('#');
while (!S_num.empty())S_num.pop();
int tnum(0);
for (int i(0)
4000
; str[i] != '\0'; ++i) {
//累加数字
if ('0' <= str[i] && str[i] <= '9') {
tnum *= 10;
tnum += str[i] - 48;
}
//遇到运算符,先把数字tnum压入S_num,然后视优先级情况而定下面的操作。
else {
S_num.push(tnum);
tnum = 0;
if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);
//运算符str[i]的优先级较高,直接压入。
else {
//将S_ch.top()弹出,一直到存在某个S_ch.top()的优先级低于str[i]。
//由于S_ch栈底部有个'#',所以不用担心S_ch弹空。
while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {
char ch = S_ch.top();
S_ch.pop();
double num1 = S_num.top();
S_num.pop();
double num2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1, num2, ch));
}//while
S_ch.push(str[i]);
}//if else
}//if else
}//for i
S_num.push(tnum);
char ch('\0');
//依次计算完所有的运算符
while ((ch = S_ch.top()) != '#') {
S_ch.pop();
double num1 = S_num.top();
S_num.pop();
double num2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1, num2, ch));
}//while
printf("%.2f\n", S_num.top());
}//while
return 0;
}//main

细节:gets_s函数,gets函数,S_ch栈底预先放置‘#’,作为优先级最低的运算符,功能上类似于“哨兵”。

Freopen(“in.txt”,”r”,stdin)是重定向语句,可以在相应位置安排in.txt文件编辑测试用例,也可以去掉改行代码,自己在控制台输入测试用例。

虽然表达式中只有整数,但是S_num里面存放的元素是double。

Compare的维度明显偏大,可以设置成compare[5][3]。

二、添加小括号。

逻辑上的主要改变就是‘(’,‘)’括号分开处理。

Str[i]为‘(’,则直接压入S_ch;如果栈顶为‘(’,任何运算符的优先级都比它大。

Str[i]为‘)’,视情况脱去跟它相匹配的那个左括号,参考main里的代码。

优先级部分参考compare[5][6]二维数组。

并且完美支持了正数和负数的处理。

比如:

把这(-2)看作是(0-2)的运算

(+2)看作是(0+2)的运算

(2)是在有个puts("here")输出那处理的,先从S_num里pop出来,稍后再压进去,用这种伎俩来统一流程。

-5+3-5这种式子的,第一个-5是看做0-5来处理的。

#include<stdio.h>
#include<stack>
using std::stack;

int ch2num(const char &ch) {
int num(-1);
switch (ch) {
case'#':num = 0; break;
case'+':num = 1; break;
case'-':num = 2; break;
case'*':num = 3; break;
case'/':num = 4; break;
case'(':num = 5; break;
case')':num = 6; break;
}//switch
return num;
}//ch2num
int operator_2(const int &num1, const int &num2, const char &ch) {
int num(-1);
switch (ch) {
case'+':num = num2 + num1; break;
case'-':num = num2 - num1; break;
case'*':num = num2 *num1; break;
case'/':num = num2 / num1; break;
}//switch
return num;
}//operator_2

int compare[5][6] = { { 0 },{ 1, 0, 0,0, 0, 1 },{ 1, 0, 0, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 } };

int main() {
freopen("in.txt", "r", stdin);
char str[250];
stack<int>S_num;
stack<char>S_ch;
while (gets_s(str)) {
while (!S_ch.empty())S_ch.pop();
S_ch.push('#');
while (!S_num.empty())S_num.pop();
int tnum(0);
for (int i(0); str[i] != '\0';) {
if ('0' <= str[i] && str[i] <= '9') {
tnum *= 10;
tnum += str[i] - '0';
++i;
}
else if(str[i] == '(') {
S_ch.push('(');
++i;
}
else if(str[i] == ')') {
S_num.push(tnum);
//deal util (
char ch = S_ch.top();
if (ch != '(') {//just one operator,if this step is ignored,so...
S_ch.pop();
int num1 = S_num.top();
S_num.pop();
int num2 = S_num.top();
S_num.pop();
tnum = operator_2(num1, num2, ch);
}
else {
//puts("here");
tnum = S_num.top();
S_num.pop();
}//if else
S_ch.pop();
++i;
}
else {
S_num.push(tnum);
tnum = 0;
if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);
else {
while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {
char ch = S_ch.top();
S_ch.pop();
int num1 = S_num.top();
S_num.pop();
int num2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1, num2, ch));
}//while
S_ch.push(str[i]);
}//ifelse
++i;
}//if else if else if else
}//for i
S_num.push(tnum);
char ch('\0');
while ((ch = S_ch.top()) != '#') {
S_ch.pop();
int num1 = S_num.top();
S_num.pop();
int num2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1, num2, ch));
}//while
printf("%d\n", S_num.top());
}//while
return 0;
}//main

三、添加实数的处理

数字累加的部分发生变化,tnum定义为double型,weight_del定义为小数部分的权重。
int main() {
freopen("in.txt", "r", stdin);
char str[250];
stack<double>S_num;
stack<char>S_ch;
while (gets_s(str)) {
while (!S_ch.empty())S_ch.pop();
S_ch.push('#');
while (!S_num.empty())S_num.pop();
double tnum(0.0);
double weight_del(0.0);
for (int i(0); str[i] != '\0'; ++i) {
if ('0' <= str[i] && str[i] <= '9' || str[i] == '.') {
if ('0' <= str[i] && str[i] <= '9') {
if (weight_del == 0.0) {
tnum *= 10;
tnum += str[i] - '0';
}
else {
tnum += weight_del*(str[i] - '0');
weight_del *= 0.1;
}//if else
}
else if(str[i] == '.')weight_del = 0.1;
}
else if(str[i] == '(')S_ch.push('(');
else if(str[i] == ')') {
S_num.push(tnum);
tnum = 0.0;
weight_del = 0.0;
//deal util (
char ch(S_ch.top());
if (ch != '(') {//justone operator,if this step is ignored,so...
S_ch.pop();
double num1 = S_num.top();
S_num.pop();
double num2 = S_num.top();
S_num.pop();
tnum = operator_2(num1, num2, ch);
}
else {
//puts("here");
tnum = S_num.top();
S_num.pop();
}//if else
S_ch.pop();//pop(
}
else {
S_num.push(tnum);
tnum = 0.0;
weight_del = 0.0;
if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);
else {
while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {
char ch = S_ch.top();
S_ch.pop();
double num1 = S_num.top();
S_num.pop();
double num2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1, num2, ch));
}//while
S_ch.push(str[i]);
}//if else
}//if else if else if else
}//for i
S_num.push(tnum);
char ch('\0');
while ((ch = S_ch.top()) != '#') {
S_ch.pop();
double num1 = S_num.top();
S_num.pop();
double num2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1, num2, ch));
}//while
printf("%f\n", S_num.top());
}//while
return 0;
}//main

四、剔除空格

如果表达式中含有多余空格的情况,需要预处理一下输入字符串str,就是剔除里面的空格,编写函数如下。

void
replace_space(char*str){

   int
i(-1), j(-1);

   for(i
= 0, j = 0;str[j] !='\0';j++)if
(str[j]!='
')

       str[i++]=str[j];

   str[i]='\0';

   return;

}//replace_space

放置在main函数中的如下位置

while (gets_s(str)){

   replace_space(str);

    。。。

}//while

五、封装calculator类

class Calculator {
private:
double result;
string input;
stack<double> S_num;
stack<char> S_ch;
const int compare[5][6] = { { 0 },{ 1, 0, 0, 0, 0, 1 },{ 1, 0, 0, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 },{ 1, 1, 1, 0, 0, 1 } };

int ch2num(const char &ch) {
int num(-1);
switch (ch) {
case '#':num = 0; break;
case '+':num = 1; break;
case '-':num = 2; break;
case '*':num = 3; break;
case '/':num = 4; break;
case '(':num = 5; break;
case ')':num = 6; break;
}//switch
return num;
}//ch2num
double operator_2(const double &num1, const double &num2, const char &ch) {
double num(-1);
switch (ch) {
case '+':num = num2 + num1; break;
case '-':num = num2 - num1; break;
case '*':num = num2 * num1; break;
case '/':num = num2 / num1; break;
}//switch
return num;
}//operator_2
void replace_space(string &str) {
int i(-1), j(-1);
for (i = 0, j = 0; str[j] != '\0'; j++) if (str[j] != ' ')
str[i++] = str[j];
str[i] = '\0';
return;
}//replace_space
void calc() {
string str(input);
replace_space(str);
if (str == "")return;
while (!S_ch.empty())S_ch.pop();
S_ch.push('#');
while (!S_num.empty())S_num.pop();
double tnum(0.0);
double weight_del(0.0);
for (int i(0); str[i] != '\0'; ++i) {
if ('0' <= str[i] && str[i] <= '9' || str[i] == '.') {
if ('0' <= str[i] && str[i] <= '9') {
if (weight_del == 0.0) {
tnum *= 10;
tnum += str[i] - '0';
}
else {
tnum += weight_del*(str[i] - '0');
weight_del *= 0.1;
}//if else
}
else if (str[i] == '.')weight_del = 0.1;
}
else if (str[i] == '(')S_ch.push('(');
else if (str[i] == ')') {
S_num.push(tnum);
tnum = 0.0;
weight_del = 0.0;
char ch(S_ch.top());
if (ch != '(') {
S_ch.pop();
double num1 = S_num.top();
S_num.pop();
double num2 = S_num.top();
S_num.pop();
tnum = operator_2(num1, num2, ch);
}
else {
tnum = S_num.top();
S_num.pop();
}//if else
S_ch.pop();
}
else {
S_num.push(tnum);
tnum = 0.0;
weight_del = 0.0;
if (compare[ch2num(str[i])][ch2num(S_ch.top())] == 1)S_ch.push(str[i]);
else {
while (compare[ch2num(str[i])][ch2num(S_ch.top())] == 0) {
char ch = S_ch.top();
S_ch.pop();
double num1 = S_num.top();
S_num.pop();
double num2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1, num2, ch));
}//while
S_ch.push(str[i]);
}//if else
}//if else if else if else
}//for i
S_num.push(tnum);
char ch('\0');
while ((ch = S_ch.top()) != '#') {
S_ch.pop();
double num1 = S_num.top();
S_num.pop();
double num2 = S_num.top();
S_num.pop();
S_num.push(operator_2(num1, num2, ch));
}//while
result = S_num.top();
return;
}//calc
public:
Calculator(string input = "") {
this->input = input;
result = 0.0;
return;
}//Calculator
void inputStr(string input) {
this->input = input;
result = 0.0;
calc();
return;
}//inputStr
double getResult() {
return result;
}//getResult
};


本文没有处理非法表达式的部分。
董艳超,第二版,20170224
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息