计算器的功能:
加+ 减- 乘* 除/ 逻辑或|| 逻辑与&& 逻辑非!
基本原理:
设计两个栈来分别储存运算符和数字,运算符栈用‘#’表示开始与结束
让运算符和数字依次入栈
出栈规则:当前入栈的运算符比栈顶的运算符优先级低
例:
12+5*(2+3)*6/2-4
代码实现
#include <iostream>
#include <stack>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int OperatorPri(char opt)//将优先级量化便于比较
{
switch(opt)
{
case '#': return 0;
case ')': return 1;
case '|':
case '&': return 2;
case '-':
case '+': return 3;
case '*':
case '/': return 4;
case '!': return 5;
case '(': return 6;
default: return -1;
}
}
int PreOrder(char opt1,char opt2)//比较两个运算符的优先级
{
int i = OperatorPri(opt1);
int j = OperatorPri(opt2);
if(opt2=='(') //( )内的 + - * / 还能进栈但是 + - * / 对应的数字小于 ( 对应的数字 所以把这里设置成 1 让()内的 + - * / 可以进栈
return 1;
if(i==-1||j==-1)
return -1;
if(i>j)
return 1;
else if(i==j)
return 0;
else
return -1;
}
bool isOpr(char *p) //判断运算公式中的字符是不是数字
{
if(*p>='0'&&*p<='9')
return true;
else return false;
}
char* getNum(char *p,int &num)//将char型字符换成数字
{
num=0;
while(isOpr(p))
{
num = 10*num + (*p-'0');
p++;
}
p--; //为了防止后面while循环中的p++跳过了运算符 !!!!!!!!!
return p;
}
int express(int e1,int e2,char opt) //运算
{
cout<<e1<< opt <<e2<<" is calculated!"<<endl;
switch(opt)
{
case '+': return e1+e2;
case '-': return e1-e2;
case '*': return e1*e2;
case '/': return e1/e2;
case '&': return e1&&e2;
case '|': return e1||e2;
case '!':return !e2; //逻辑非运算符是单目运算符要进行特殊处理(仅进行一个数的运算,另外一个出栈的数据在重新入栈)
default: cout<<"wrong"<<endl;
}
}
int Calc(char *s)
{
int x; //用来储存 express(e1,e2,opt) 要不然输出两边 cout<<e1<< opt <<e2<<" is calculated!"<<endl;
bool flag=false; //要用来判断最终两个栈是否为空
stack<char> opt; //用来储存运算符的栈
char c; //用来保存 get_top()数据
stack<int> opr; //用来储存数字的栈
int e1,e2,e; //用来保存 get_top e 用来压入数据
opt.push('#');
opr.push(1); //为了防止第一个运算符便是逻辑非(!运算符采用出栈两个数据进行一个数据的运算,另外一个重新入栈,这样便保持了单目运算符和双目运算符的一致性,而刚开始数据栈里面先储存个1,便是为了防止第一个运算符便是!的情况,1不参与任何的运算)
cout<<'#'<<" is pushed"<<endl;
char *p = s; //初始化p
while(*p!='#')
{
if(isOpr(p)) //把字符转化为数字并入数字栈
{
p = getNum(p,e);
opr.push(e);
cout<<e<<" is pushed"<<endl;
}
else //如果不是数字而是运算符,则对此运算符和栈顶运算符的优先级进行比较
{
c = opt.top();
if(PreOrder(*p,c)>0) //当前入栈的运算符比栈顶的运算符优先级高则入栈
{
opt.push(*p);
cout<<*p<<" is pushed"<<endl;
}
else //当前入栈的运算符比栈顶的运算符优先级低则栈顶运算符出栈并出栈两个数据进行计算
{
opt.pop();
cout<<c<<" is poped"<<endl;
e1 = opr.top();
opr.pop();
cout<<e1<<" is poped"<<endl;
e2 = opr.top();
opr.pop();
cout<<e2<<" is poped"<<endl;
x = express(e2,e1,c);
if(c == '!') //若是逻辑非运算符,则只需要一个数据参与运算,另外一个数据再入栈
{
opr.push(e2);
cout<<e2<<" is pushed"<<endl;
}
opr.push(x); //结果入栈
cout<<x<<" is pushed"<<endl;
if(*p=='+'||*p=='-'||*p=='*'||*p=='/'||*p=='&'||*p=='|'||*p=='!') //在进行了一次数据和运算符出栈计算后,*p对应的那个运算符还要继续进栈
{
opt.push(*p);
cout<<*p<<" is pushed"<<endl;
}
if(*p==')')
{
c = opt.top(); //先判断这是否是个空括号
if(c!='(')
{
c = opt.top();
opt.pop();
cout<<c<<" is poped"<<endl;
e1 = opr.top();
opr.pop();
cout<<e1<<" is poped"<<endl;
e2=opr.top();
opr.pop();
cout<<e2<<" is poped"<<endl;
x = express(e2,e1,c);
if(c == '!')
{
opr.push(e2);
cout<<e2<<" is pushed"<<endl;
}
opr.push(x);
cout<<x<<" is pushed"<<endl;
c = opt.top();
opt.pop();
cout<<c<<" is poped"<<endl;
}
else
{
opt.pop();
cout<<c<<" is poped"<<endl;
}
}
}
}
p++;
}
if(*p=='#')
{
c = opt.top();
opt.pop();
cout<<c<<" is poped"<<endl;
e1 = opr.top();
opr.pop();
cout<<e1<<" is poped"<<endl;
e2 = opr.top();
opr.pop();
cout<<e2<<" is poped"<<endl;
x = express(e2,e1,c);
if(c == '!')
{
opr.push(e2);
cout<<e2<<" is pushed"<<endl;
}
opr.push(x);
cout<<x<<" is pushed"<<endl;
c = opt.top();
opt.pop();
cout<<c<<"is poped"<<endl;
while(c!='#')
{
cout<<c<<" is poped"<<endl;
e1 = opr.top();
opr.pop();
cout<<e1<<" is poped"<<endl;
e2 = opr.top();
opr.pop();
cout<<e1<<" is poped"<<endl;
x = express(e2,e1,c);
if(c == '!')
{
opr.push(e2);
cout<<e2<<" is pushed"<<endl;
}
opr.push(x);
cout<<x<<" is pushed"<<endl;
c = opt.top();
opt.pop();
cout<<c<<" is poped"<<endl;
}
e = opr.top();//最终结果
opr.pop();
cout<<"e is"<<e<<endl;
if(opt.empty()&&opr.size()==1) //数据栈中还有一个'1'没出栈
flag = true;
if(flag)
return e;
else
return -1;
}
}
int main()
{
//char mychar[100]={'1','2','+','5','*','(','2','+','3',')','*','6','/','2','-','4','#'};
char mychar[100]={'!','3','+','2','*','5','#'};
cout<<Calc(mychar)<<endl;
return 0;
}
运行结果
总结
近期要进行数据结构的期末考,因此翻出曾经的作业内容进行复习。本篇文章中的代码原本是我们的一份作业,我借鉴了一位前辈的代码,这位前辈写了 + - * /四则运算的计算器,我在他的基础上加上了 && || !三个运算符。由于时间跨度较大,我已经找不到前辈的文章了,若各位找到了这位前辈的文章,可以回复我,我会贴上地址,麻烦各位了,谢谢。
欢迎各位指正,谢谢。