下面介绍两种使用C++和栈实现简易计算器的代码,主要参照 c++利用栈实现简单计算器、利用栈实现简易计算器(含代码) 和 C++利用栈实现计算器 三篇博文进行的总结和归纳,如有需要可以点击链接查看原文。
方法一:
使用两个栈结构,一个存数字,一个存运算符。
为了实现用栈计算算数表达式的值,需设置两个工作栈:用于存储运算符的栈fn,以及用于存储操作数及中间结果的栈num。
计算步骤:
- 定义index对表达式进行扫描; 创建两个栈,一个栈存放数字,称为数栈(num);一个栈存放符号,称为符号栈(fn);
- 当遇到数字时,入数栈;(注意字符位数,数字有可能是多位数)
2.1 若是字符串最后一个的时候,直接入数栈
2.2 若不是最后一个字符,需要再往后判断一位,若后一位不是符号,继续遍历,并将该字符拼接;若是则进数栈 - 当遇到符号时,入符号栈
3.1如果符号栈为空,则直接入栈
3.2如果符号栈不为空;则需要判断优先级;
3.2.1判断优先级,若当前符号的优先级小于栈顶符号的优先级,则栈顶符号出栈,同时数栈中两个数字出栈;进行计算,得出的结果入数栈,当前符号入栈。
3.2.2若优先级大于前一个符号,则继续进行入栈操作。 - 当表达式遍历完后,则两个数字、一个符号依次出栈,进行操作,最后栈中剩的最后一个数为结果
代码部分
#include<bits/stdc++.h>
using namespace std;
int prio(char ch) //运算符优先级判定
{
switch(ch)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '(':
return 3;
case ')':
return 4;
}
}
double oper(double a,double b,char ch) //进行运算
{
switch(ch)
{
case '+':
return a+b;
case '-':
return a-b;
case '*':
return a*b;
case '/':
return a/b;
}
}
int main()
{
stack<double>num; //用来存储运算数字
stack<char>fh; //用来存储运算符
string ll;
cin>>ll;
double dit=0;
for(int i=0;i<ll.size();i++){
if(ll[i]>='0'&&ll[i]<='9') //截取数字
{
dit=dit*10+(ll[i]-'0');
if(ll[i+1]<'0'||ll[i+1]>'9'||i==ll.size()-1){ //当下一位为符号时或当前位为最后一位时
num.push(dit);
dit=0;
}
}
else{
if(fh.size()==0){
fh.push(ll[i]);
continue;
}
else{
if(prio(ll[i])==4){ //处理括号部分
while(fh.top()!='(')
{
char tt=fh.top();
fh.pop();
double b=num.top();
num.pop();
double a=num.top();
num.pop();
num.push(oper(a,b,tt));
}
fh.pop(); //将左括号弹出栈
continue;
}
else if(prio(ll[i])<=prio(fh.top())&&prio(fh.top())!=3) //当前运算符的优先级低于或等于栈顶运算符优先级时
{
char tt=fh.top();
fh.pop();
fh.push(ll[i]);
double b=num.top();
num.pop();
double a=num.top();
num.pop();
num.push(oper(a,b,tt));
continue;
}
else
{
fh.push(ll[i]);
}
}
}
}
while(!fh.empty())
{
char tt=fh.top();
fh.pop();
double b=num.top();
num.pop();
double a=num.top();
num.pop();
num.push(oper(a,b,tt));
}
//cout<<num.size()<<endl;
//cout<<fh.size()<<endl;
cout<<num.top()<<endl;
return 0;
}
方法二:
先使用一个符号栈来将中缀表达式转换为后缀表达式,再使用一个数字栈来计算后缀表达式的结果。
整体步骤
- 中缀表达式转后缀表达式
- 计算后缀表达式
第一步:中缀表达式转后缀表达式
自左向右读入中缀表达式
- 若为数字时,加入后缀表达式;
- 运算符:
若为 ‘(’,入栈
若为 ‘)’,则依次把栈中的的运算符加入后缀表达式中,直到出现’(’,从栈中删除’(’
若为除括号外的其他运算符, 当其优先级高于除’('以外的栈顶运算符时,直接入栈。否则从栈顶开始,依次弹出比当前处理的运算符优先级高和优先级相等的运算符,直到一个比它优先级低的或者遇到了一个左括号为止,然后将其自身压入栈中(先出后入)。 - 当扫描的中缀表达式结束时,栈中的的所有运算符出栈;
具体示意图如下:
第二步: 计算后缀表达式
建立一个栈S 。从左到右读表达式,如果读到操作数就将它压入栈S中,如果读到n元运算符(即需要参数个数为n的运算符)则取出由栈顶向下的n项按操作数运算,再将运算的结果代替原栈顶的n项,压入栈S中 。如果后缀表达式未读完,则重复上面过程,最后输出栈顶的数值则为结束。
简言之:
- 从左到右读表达式
- 遇到操作数压入栈中
- 遇到操作符取并弹出栈顶n个元素,(n取决于操作符是n元操作符),计算结果压入栈中
- 后缀表达式读完,当前栈顶元素及为结果
C++代码实现
#include <iostream>
#include<stack>
#include <sstream>
#include<stdlib.h>
using namespace std;
double CalSuffix(string suffix)
{
double result;
stack<double> number;
int i = 0,j;
int n=0;//判断是否为数字
string current;
while(suffix[i]!='#')
{
int isNum=0;
if(suffix[i]=='|')
{
for(j=i+1;; j++)
{
if(suffix[j]=='|')
break;
if(suffix[j]=='#')
break;
}
//获取|A|之间元素
for(int k=i+1; k<j; k++)
{
current+=suffix[k];
}
//判断是否为数值
for(int k=0; k<current.size(); k++)
{
if(current[k]>=48 && current[k]<=57)//数字
{
//strinf转double
istringstream iss(current);
double num;
iss >> num;
number.push(num);
isNum = 1;
break;
}
}
if(isNum!=1){
double n2 = number.top();
number.pop();
double n1 = number.top();
number.pop();
if(current=="+"){
number.push(n1+n2);
}
else if(current=="-"){
number.push(n1-n2);
}
else if(current=="*"){
number.push(n1*n2);
}
else if(current=="/"){
number.push(n1/n2);
}
}
current="";//清空当前字符串;
}
i++;
}
if(number.size()!=1)
cout<<"输入有误"<<endl;
// else
return number.top();
}
int Priority(char operate)//栈中优先级
{
switch(operate)
{
case '+':
case '-':
return 2;
case '*':
case '/':
return 3;
case '(':
case ')':
return 1;
default:
return 0;
}
}
string Infix2Suffix(string Infix)
{
stack<char> operate;
string Suffix = " ";//初始化后缀表达式
char currentOp;
int negative;
int i = 0,j = 0;//i为中缀当前指向 j为后缀当前指向
while(Infix[i]!='\0')
{
if(i+1!='\0')
negative = 0;
if(Infix[i]>=48 && Infix[i]<=57) //判断数字
{
Suffix[j++] = '|';//j是后缀表达索引
Suffix[j++] =Infix[i];//存储当前数字并指向下一个
while(Infix[++i]>=48 && Infix[i]<=57) //整数部分
{
Suffix[j++] =Infix[i];
}
if(Infix[i]=='.') //是小数
{
Suffix[j++]='.';
i+=1;//中缀索引 往后移
while(Infix[i]>=48 && Infix[i]<=57) //小数部分
{
Suffix[j++] =Infix[i];
i+=1;
}
}
}
else if(Infix[i]=='(')//如果读入(,因为左括号优先级最高,因此放入栈中,但是注意,当左括号放入栈中后,则优先级最低。
{
operate.push(Infix[i++]);
}
else if(Infix[i]==')')//如果读入),则将栈中运算符取出放入输出字符串,直到取出(为止,注意:()不输出到输出字符串。
{
if(operate.empty())//没有左括号
cout<<"表达式错误"<<endl;
else
{
currentOp = operate.top();
while(currentOp!='(')
{
cout<<currentOp<<endl;
Suffix[j++]='|';
Suffix[j++]=currentOp;
operate.pop();
if(operate.empty())
{
cout<<"表达式错误"<<endl;
break;
}
currentOp = operate.top();
}
operate.pop();//删除栈中(
i++;
}
}
else if(Infix[i]=='+'||Infix[i]=='-'||Infix[i]=='/'||Infix[i]=='*')
{
//判断负数
if(Infix[i]=='-')
{
if(i==0)//第一个为‘-’时为负号
negative = 1;
else if(Infix[i-1]=='+'||Infix[i-1]=='-'||Infix[i-1]=='/'||Infix[i-1]=='*')//如果前面有操作符则为负号
negative = 1;
if(negative==1)
{
Suffix[j++] = '|';//负号
Suffix[j++] = '-';
i+=1;
if(Infix[i]>=48 && Infix[i]<=57) //判断数字
{
Suffix[j++] =Infix[i];
while(Infix[++i]>=48 && Infix[i]<=57) //整数部分
{
Suffix[j++] =Infix[i];
}
if(Infix[i]=='.') //是小数
{
Suffix[j++]='.';
i+=1;
while(Infix[i]>=48 && Infix[i]<=57) //小数部分
{
Suffix[j++] =Infix[i];
i+=1;
}
}
}
continue;
}
}
//如果读入一般运算符如+-*/,则放入堆栈,但是放入堆栈之前必须要检查栈顶
if(operate.empty())
{
operate.push(Infix[i++]);
}
else
{
char top = operate.top();//栈顶
if(Priority(top)<Priority(Infix[i])) //放入的符号优先级低于栈顶
{
operate.push(Infix[i++]);//放入栈顶并指向下一个
}
else//如果放入的优先级较低,则需要将栈顶的运算符放入输出字符串。
{
while(Priority(top)>=Priority(Infix[i]))
{
Suffix[j++]='|';
Suffix[j++]=top;
operate.pop();
if(!operate.empty())
{
top = operate.top();
}
else
break;
}
operate.push(Infix[i++]);//放入栈顶并指向下一个
}
}
}
else
{
cout<<"符号错误"<<endl;
i+=1;
}
}
//顺序读完表达式,如果栈中还有操作符,则弹出,并放入输出字符串。
while(!operate.empty())
{
char to = operate.top();
Suffix[j++]='|';
Suffix[j++]=to;
operate.pop();
}
Suffix[j] = '#';//结束符
cout<<Suffix<<endl;
return Suffix;
}
int main()
{
string a;
cin>>a;
istringstream iss(a);
double num;
iss >> num;
cout<<num;
cout<<"后缀为:"<<Infix2Suffix(a)<<endl;
cout<<CalSuffix(Infix2Suffix(a));
return 0;
}
Reference
方法1原文链接: c++利用栈实现简单计算器
方法1理论链接: 利用栈实现简易计算器(含代码)
方法2原文链接: C++利用栈实现计算器