1、不带括号的四则运算
引用自博客:面试题45:字符串四则运算的实现
题目:有字符串表示的一个四则运算表达式,要求计算出该表达式的正确数值。
说明:
- 四则运算即加减乘除"±*/"
- 该表达式中的数字只能是1位(数值范围0~9)
- 另若有不能整除的情况,按向下取整处理,eg: 8/3得出值为2。
例如:若有字符串"8+7*2-9/3",计算出其值为19。
代码:
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
int cal(int nNum1, char op, int nNum2)
{
if(op == '+')
{
return nNum1 + nNum2;
}
if(op == '-')
{
return nNum1 - nNum2;
}
if(op == '*')
{
return nNum1 * nNum2;
}
if(op == '/')
{
return nNum1 / nNum2;
}
}
int calculate(int len, char *expstr)
{
assert(expstr);
if(len < 3)
{
return -1;
}
char *p = expstr;
int nNum1 = p[0] - '0';
char op = p[1];
int nNum2 = p[2] - '0';
p += 3;
while(*p)
{
if(*p=='*' || *p=='/')
{
if(op =='*' || op=='/')
{
nNum1 = cal(nNum1, op, nNum2);
op = *p;
nNum2 = p[1] - '0';
}
else
{
nNum2 = cal(nNum2, *p, p[1]-'0');
}
}
else
{
nNum1 = cal(nNum1, op, nNum2);
op = *p;
nNum2 = p[1] - '0';
}
p += 2;
}
return cal(nNum1, op, nNum2);
}
int main()
{
//char str[] = "1+2*3/5-6*7";
//char str[] = "8+7*2-9/3";
char str[] = "3/2*2+3*4";
int res = calculate(strlen(str), str);
printf("result: %d\n", res);
}
2、带括号的四则运算
引用自博客:C/C++带括号四则运算
(1).首先从string读入表达式,取出每一个字符后装入deque容器coll1中(源码在后面)。
(2).从该容器取出每一个元素,利用栈将中缀表达式转换成后缀表达式(可参考:http://blog.csdn.net/anye3000/article/details/7939203),将后缀表达式装入容器coll3中。
(3).最后从coll3中取出元素逐一处理,既使用逆波兰式求值(如下图)。
#include<stack>
#include<iostream>
#include<deque>
#include<string>
using namespace std;
//判断是否为括号
bool isPra(char c)
{
if(c=='('||c==')')
return true;
else
return false;
}
//获得符号的优先性
int getPri(char c)
{
switch(c)
{
case '+':
case '-':
return 0; //如果是加减,返回0
break;
case '*':
case '/':
return 1; //如果是乘除,返回1
break;
case '(':
case ')':
return -1; //注意,这里将括号设为最低优先级,因此括号不会被弹出,除非遇到右括号
break;
}
}
//判断符号的优先性
void check(char c, stack<char>& coll2, deque<char>& coll3)
{
if(coll2.empty())
{
coll2.push(c);
return;
}
if(isPra(c))
{
if(c=='(')
coll2.push(c);
else
{
//弹出所有元素直到遇到左括号
while(coll2.top()!='(')
{
char ch = coll2.top();
coll3.push_back(ch);
coll2.pop();
}
//当遇到左括号时,弹出但不加入coll3(后缀表达式中)
coll2.pop();
}
}
else //如果不是括号
{
//取出栈顶元素,与当前符号进行优先性比较
char sym = coll2.top();
//比较两符号的优先性
if(getPri(c)<=getPri(sym))
{
//如果c的优先性比栈顶符号小或等于,弹出栈顶元素
coll2.pop();
//并将其压入coll3(后缀表达式)中
coll3.push_back(sym);
//递归调用check,比较当前符号c与下一个栈顶符号的优先性
check(c,coll2,coll3);
}
else
{
//如果c比栈顶符号优先级大,那将c压入coll2(操作符栈)中
coll2.push(c);
}
}
}
//从coll中取出元素,分配元素到coll2和coll3中
void allocate(deque<char>& coll1, stack<char>& coll2, deque<char>& coll3)
{
while(!coll1.empty())
{
char c = coll1.front();
coll1.pop_front();
if(c>='0'&&c<='9')
{
coll3.push_back(c);
}
else
{
//调用check函数,针对不同情况作出不同操作
check(c,coll2,coll3);
}
}
//如果输入结束,将coll2的元素全部弹出,加入后缀表达式中
while(!coll2.empty())
{
char c = coll2.top();
coll3.push_back(c);
coll2.pop();
}
}
//计算后缀表达式
void calculate(deque<char>& coll3, stack<int>& coll4)
{
while(!coll3.empty())
{
char c = coll3.front();
coll3.pop_front();
//如果是操作数,压入栈中
if(c>='0'&&c<='9')
{
//减去'0'得出偏移值,即为真实数值(如果直接转换成int,结果不对,因为char 转换为int是其编码值,例如'1'的编码值为49
int op = c-'0';
coll4.push(op);
}
else //如果是操作符,从栈中弹出元素进行计算
{
int op1 = coll4.top();
coll4.pop();
int op2 = coll4.top();
coll4.pop();
switch(c)
{
case '+':
coll4.push(op2+op1);
break;
case '-':
coll4.push(op2-op1);
break;
case '*':
coll4.push(op2*op1);
break;
case '/':
coll4.push(op2/op1); //注意是op2(op)op1而不是op1(op)op2
break;
}
}
}
}
int main()
{
deque<char> coll1; //盛放中缀表达式
stack<char> coll2; //盛放操作符
deque<char> coll3; //盛放后缀表达式
stack<int>coll4; //计算后缀表达式的辅助容器
string str;
cout<<"请输入表达式,按enter结束:"<<endl;
cin>>str;
for(int i=0;i!=str.size();++i)
{
//逐一加入每个字符,这里使用deque因为deque在两端删除添加的速度最快
coll1.push_back(str[i]);
}
//从coll中取出元素,分配元素到coll2和coll3中
allocate(coll1,coll2,coll3);
//计算后缀表达式
calculate(coll3,coll4);
cout<<"计算结果为:"<<coll4.top()<<endl;
}
3、带括号的四则运算(简单计算器)
引用自博客:简单四则运算计算器的C++实现(含括号和±*/的优先级判断)
算数运算符在压栈和出栈时的优先关系
main.cpp
// main.cpp
#include "Calculator.h"
int main(int argc, char *agrv[])
{
CCalculator cc;
cout << "/\n"\
<< "// Hello, Dear User! Welcome to Calculator! //\n"\
<< "// Tips: Calc - Input any Equation end by \"Enter\" //\n"\
<< "// Exit - exit //\n"\
<< "/\n"\
<< "Input your equation pls:\nUsr/> ";
string eq;
while (getline(std::cin, eq))
{
if (!eq.compare("exit"))
{
cout << "/\n"\
<< "// Goodbye! Dear User!!! //\n"\
<< "/\n";
break;
}
cout << "Sys/> "<< cc.CalcEquation(eq) << "\n\nUsr/> ";
}
return 0;
}
Calculator.h
// Calculator.h
#ifndef _CALCULATOR_H_
#define _CALCULATOR_H_
#include <stack>
#include <math.h>
#include <iostream>
#include <sstream>
using namespace std;
/***********************************************************************
类 描 述: CCalculator - 计算器类,对外提供等式计算接口,并返回计算结果,可重复
调用,计算不同等式;
编辑时间:2016/12/26
编 辑 者:Chirl
***********************************************************************/
class CCalculator
{
public:
CCalculator(void);
~CCalculator(void);
/***********************************************************************
函数功能:对传入的字符串等式进行求解。
输入参数:eq - 字符串格式的数学算式
输出参数:返回算式计算结果;
编辑时间:2016/12/28
编 辑 者:Chirl
***********************************************************************/
const float CalcEquation(string &eq);
private:
CCalculator(const CCalculator &c){}
void operator=(const CCalculator &c){}
/***********************************************************************
函数功能:对两个操作数lhs和rhs执行op算数操作。
输入参数:op必须为算数操作符(+、-、*、/)
rhs和lhs必须为同类型的值;
输出参数:返回两个数进行op算数运算后的结果;
编辑时间:2016/12/26
编 辑 者:Chirl
***********************************************************************/
template<class T> T Operate(T lhs, char op, T rhs) const;
/***********************************************************************
函数功能:判断字符c是否为算数运算符;
输入参数:c - 待判断的字符;
输出参数:如果c是算数操作符中的值,则返回true,否则false;
编辑时间:2016/12/26
编 辑 者:Chirl
***********************************************************************/
bool IsOperator(char c) const;
/***********************************************************************
函数功能:查询运算符的下标;
输入参数:c - 待查询的字符;
输出参数:如果c为运算符,则返回0~6,否则返回7;
编辑时间:2016/12/26
编 辑 者:Chirl
***********************************************************************/
int FindOperatorIdx(char c) const;
/***********************************************************************
函数功能:比较两个算数运算符的优先级;
输入参数:bcp - 被比较的运算符;
cp - 待比较的算数运算符;
输出参数:如果cp优先级高,返回'<';cp优先级低,返回'>';
编辑时间:2016/12/28
编 辑 者:Chirl
***********************************************************************/
char ComparePriority(char bcp, char cp) const;
/***********************************************************************
函数功能:根据优先级,对栈中的数据进行操作;
输入参数:priority - 优先级符号,< > =;
op - 当前待操作的操作符;
输出参数:bool 返回对当前的操作符是否运算结束;即当前的操作符是否已经成功入栈:
编辑时间:2016/12/28
编 辑 者:Chirl
***********************************************************************/
bool OperateDependOnPriority(const char priority, char op);
private:
typedef struct SOperatorPriority
{
char op; // 运算符;
char pri; // 优先级;
}SOP;
enum EOP // 基础运算符
{
EOP_PLUS = 0, // +
EOP_MINUS = 1, // -
EOP_MULTI = 2, // *
EOP_DIVID = 3, // /
EOP_LBRACKET = 4, // (
EOP_RBRACKET = 5, // )
EOP_SHAP = 6, // #
EOP_OPCNT = 7, // 操作符个数;
};
const static SOP s_OP[EOP_OPCNT]; // 存储基本算数运算符;
const static char s_OpPriorityTable[EOP_OPCNT][EOP_OPCNT]; // 操作符优先级列表;
stack<char> m_OptrStack; // 操作符栈;
stack<float> m_NumStack; // 数值栈;
bool m_EquationErr; // 输入的等式有误;
};
template<class T> // 基础四则运算的函数模板在此其实没有必要,直接令类型为float也行;
T CCalculator::Operate(T lhs, char op, T rhs) const
{
switch (op)
{
case '+':
return lhs + rhs;
case '-':
return lhs - rhs;
case '*':
return lhs * rhs;
case '/':
return abs(rhs-0)<0.000001f ? 0xFFFFFFF : lhs / rhs;
default:
cout << "Calc/> Your operator is wrong!" << endl;
break;
}
return T();
}
#endif
Calculator.cpp
// Calculator.cpp
#include "Calculator.h"
const CCalculator::SOP CCalculator::s_OP[EOP_OPCNT] = {{'+', EOP_PLUS}, {'-', EOP_MINUS}, \
{'*', EOP_MULTI}, {'/', EOP_DIVID}, {'(', EOP_LBRACKET}, {')', EOP_RBRACKET}, {'#', EOP_SHAP}};
// 为了偷懒,直接将优先级列表存下来,用到直接查询;当然最好总结一下其中的逻辑关系,封装成函数;
const char CCalculator::s_OpPriorityTable[EOP_OPCNT][EOP_OPCNT] =
{
{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=',' '}, // ' ' 表示表达式错误;
{'>','>','>','>',' ','>','>'},
{'<','<','<','<','<',' ','='}
};
CCalculator::CCalculator(void)
: m_EquationErr(false)
{
}
CCalculator::~CCalculator(void)
{
}
const float CCalculator::CalcEquation(string &eq)
{
if (eq.empty())
{
return 0.0f;
}
// 执行预处理;
size_t idx = eq.find_first_of("="); // 去除等号;
if (idx != string::npos) // npos在这儿表示没有匹配值;
{
eq[idx] = ' ';
}
m_NumStack.swap(stack<float>());
m_OptrStack.swap(stack<char>());
m_OptrStack.push('#');
m_EquationErr = false;
eq.append("#");
float tmpNum = 0.0f; //临时保存数值:
char tmpOp = ' '; //临时保存操作符;
int curIdx = 0; //当前读取到的字符下标;
bool numAdj = false;//两个数字相邻,中间没有符号;
istringstream is(eq);
while (!is.eof() && tmpOp != '#')
{
char c;
if ((curIdx = is.tellg()) == string::npos)
{
break;
}
c = (is.str())[curIdx];
if (c >= '0' && c <= '9') // 当前位置为数值;
{
if (numAdj)
{
cout << "Calc/> The equation you input is wrong!" << endl;
return 0.0f;
}
tmpNum = 0;
is >> tmpNum;
m_NumStack.push(tmpNum);
numAdj = true;
}
else if (IsOperator(c)) // 如果是操作符;
{
tmpOp = ' ';
is >> tmpOp;
char priority = ' ';
numAdj = false;
do
{
priority = ComparePriority(m_OptrStack.top(), tmpOp);
if (priority == ' ' || m_EquationErr)
{
cout << "Calc/> The equation you input is wrong!" << endl;
return 0.0f;
}
} while (!OperateDependOnPriority(priority, tmpOp));
}
else if (c == ' ')
{
is.seekg(curIdx+1, ios::beg);
}
else
{
cout << "Calc/> The equation you input is wrong!" << endl;
return 0.0f;
}
}
if (!m_OptrStack.empty() || m_NumStack.size() != 1)
{
cout << "Calc/> The equation you input is wrong!" << endl;
return 0.0f;
}
return m_NumStack.top();
}
bool CCalculator::IsOperator(char c) const
{
return FindOperatorIdx(c) < EOP_OPCNT ? true : false;
}
int CCalculator::FindOperatorIdx(char c) const
{
int i = 0;
while (c != s_OP[i].op && i < EOP_OPCNT)
{
i++;
}
return i;
}
char CCalculator::ComparePriority(char bcp, char cp) const
{
int bidx = FindOperatorIdx(bcp);
if (bidx >= EOP_OPCNT)
{
return ' ';
}
int cidx = FindOperatorIdx(cp);
if (cidx >= EOP_OPCNT)
{
return ' ';
}
return s_OpPriorityTable[bidx][cidx];
}
bool CCalculator::OperateDependOnPriority(const char priority, char op)
{
switch (priority)
{
case '<': // 新操作符优先级大
m_OptrStack.push(op);
return true;
case '>':
{
if (m_NumStack.size() < 2) // 如果剩余数字不足以参与运算,则等式有误;
{
m_EquationErr = true;
return false;
}
float rhs = m_NumStack.top();m_NumStack.pop();
float lhs = m_NumStack.top();m_NumStack.pop();
m_NumStack.push(Operate(lhs, m_OptrStack.top(), rhs));
m_OptrStack.pop();
return false;
}
case '=':
m_OptrStack.pop();
return true;
default:
m_EquationErr = true;
break;
}
return false;
}