C++带括号的四则运算

1、不带括号的四则运算


引用自博客:面试题45:字符串四则运算的实现

题目:有字符串表示的一个四则运算表达式,要求计算出该表达式的正确数值。

说明:

  1. 四则运算即加减乘除"±*/"
  2. 该表达式中的数字只能是1位(数值范围0~9)
  3. 另若有不能整除的情况,按向下取整处理,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;
}


  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值