中缀表达式转后缀表达式

  栈的使用场景之一,中缀表达式转为后缀表达式。

  后缀表达式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,从左向右进行,转为后缀表达式后,将可以不再考虑运算符的优先规则,显然这才符合计算机的思维。

  将中缀表达式拆分成各个数字和运算符,并去除了括号,存到数组(或者容器、队列)中,遍历之:

  1. 若是数字,直接存放到用于输出的数组(或者容器、队列)中
  2. 若是”(“压栈
  3. 若是”)”持续出栈,直至出栈的是”(“或者栈为空(括号不输出,直接丢弃)
  4. 若是加减乘除运算符,则与栈顶运算符比较,当前运算符若大于栈顶运算符,则将当前运算符入栈;当前运算符若小于等于栈顶运算符,
则将栈顶运算符出栈
  5. 遍历完毕之后,将栈中的所有运算符都出栈

  计算后缀表达式的算法为:遍历后缀表达式中的数字和运算符,
  1. 若是数字,进栈
  2. 若是运算符:
  (1) 从栈中弹出右操作数
  (2) 从栈中弹出左操作数
  (3) 根据运算符进行运算
  (4) 将运算结果压入栈中
  3. 遍历结束后,栈中的唯一数字为运算结果

  下面是用c++写的四则运算表达式的计算程序:

//calculate.h
#ifndef __CALCULATE_H__
#define __CALCULATE_H__

#include <iostream>
#include <cstdlib>
#include <string>
#include <sstream>
#include <stack>
#include <vector>

class calculate
{
private:
    bool toDouble(std::string &str, double &dat);
    int prioroty(std::string c);

public:
    void split(std::string str, std::vector<std::string> &vec);
    bool MatchBrackets(std::vector<std::string>& vec);
    void transform(std::vector<std::string>& in, std::vector<std::string>& out);
    std::string cal(std::vector<std::string>& in);
    std::string cal(std::string l, std::string op, std::string r);
};

#endif /* __CALCULATE_H__ */

//calculate.cpp
#include "calculate.h"

//分隔表达式字符串,存至vec容器中
void calculate::split(std::string str, std::vector<std::string> &vec)
{
    std::string num = "";
    std::string pre = "";

    for (int i = 0; i < str.length(); i++)
    {
        //判断是否是数字/点
        if (str[i] <= '9' && str[i] >= '0' || str[i] == '.')
        {
            num += str[i];
            pre = str[i];
        }
        else if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' || str[i] == '(' || str[i] == ')')
        {
            if (num.length() != 0)
            {
                vec.push_back(num);
                num.clear();        
            }

            if ((str[i] == '+' || str[i] == '-') && ((pre == "") || (pre == "(") || (pre == ")") || pre == "+" || pre == "-" || pre == "*" || pre == "/" || pre == "(" || pre == ")" ))
            {
                //printf("%c!!\n", str[i].c_str());
                num += str[i];
                //printf("-- %c!!\n", str[i].c_str());
            }
            else
            {
                char c = str[i];
                std::string tmp;
                std::stringstream stream;
                stream << c;
                tmp = stream.str();
                vec.push_back(tmp); 
            }

            pre = str[i];
        }
    }
    if (num.length())
    {
        vec.push_back(num);
    }
}

//匹配vec容器中的括号是否匹配
bool calculate::MatchBrackets(std::vector<std::string>& vec)
{
    int len = vec.size();
    std::stack<std::string> stack;
    bool ret = true;

    for (int i = 0; i < len; i++)
    {
        if ("(" == vec[i])
        {
            stack.push(vec[i]);
        }           
        else if (vec[i] == ")")
        {
            if (!stack.empty() && "(" == stack.top())
                stack.pop();
            else
            {
                ret = false;
                break;
            }   
        }               
    }
    return ret && stack.empty();
}

//将string转为double
bool calculate::toDouble(std::string &str, double &dat)
{   
    //std::cout << dat << std::endl;
    std::stringstream stream(str);  
    stream >> dat;
    if (!dat)
        return false;
    return true;
}

//判断运算符优先级
int calculate::prioroty(std::string c)
{
    if ((c == "+") || (c == "-"))
        return 1;

    if ( (c == "*") || (c == "/"))
        return 2;

    return 0;
}

//将中缀表达式转为后缀表达式
void calculate::transform(std::vector<std::string>& in, std::vector<std::string>& out)
{
    int len = in.size();
    double dat;
    std::stack<std::string> stack;
    bool ret = true;

    if(MatchBrackets(in))
    {
        for (int i = 0; i < len; i++)
        {
            if (toDouble(in[i], dat))
            {
                //printf("in[i] = %s\n", in[i].c_str());
                out.push_back(in[i]);//若是数字直接加入输出字符串中
            }
            else if (in[i] == "+" || in[i] == "-" || in[i] == "*" || in[i] == "/")  //若是+-*/            
            {
                while (!stack.empty() && prioroty(in[i]) <= prioroty(stack.top()))  //是否需要出栈
                {
                    out.push_back(stack.top());
                    stack.pop();
                }

                stack.push(in[i]);
            }
            else if (in[i] == "(")      //若是左括号直接进栈
            {
                stack.push(in[i]);
            }
            else if (in[i] == ")")  //若是右括号,则将栈中所有左括号前的符号出栈
            {
                while (!stack.empty() && stack.top() != "(")
                {
                    out.push_back(stack.top());
                    stack.pop();
                }

                if (!stack.empty())     //丢弃括号
                {
                    stack.pop();
                }
            }
            else
            {
                //std::cout << "expression[i] = " << expression[i] << std::endl;
                ret = false;
            }

        }

        while (!stack.empty())
        {
            out.push_back(stack.top());
            stack.pop();
        }


        if( !ret )
        {
            std::cout << "false!!" << std::endl;
            out.clear();
        }
    }

}

//将两个string类型的参数转为double,并执行op(+-*/)运算,返回运算符string类型的运算结果
std::string calculate::cal(std::string l, std::string op, std::string r)
{

    std::string ret = "error";
    double ldat, rdat, tmp_ret; 
    char tmpstr[256] = {};

    if (toDouble(l, ldat) && toDouble(r, rdat))
    {
        if (op == "+")
        {
            tmp_ret = ldat + rdat;
            sprintf(tmpstr, "%lf", tmp_ret);
            ret = tmpstr;
        }
        else if (op == "-")
        {
            tmp_ret = ldat - rdat;
            sprintf(tmpstr, "%lf", tmp_ret);
            ret = tmpstr;
        }
        else if (op == "*")
        {
            tmp_ret = ldat * rdat;
            sprintf(tmpstr, "%lf", tmp_ret);
            ret = tmpstr;
        }
        else if (op == "/")
        {
            const double p = 0.0000000000001;

            if ((-p < rdat) && (rdat < p))
            {
                ret = "error";
            }
            else
            {
                tmp_ret = ldat / rdat;
                sprintf(tmpstr, "%lf", tmp_ret);
                ret = tmpstr;

            }               
        }
    }
    else
        ret = "error";

    return ret;
}

//计算后缀表达式
std::string calculate::cal(std::vector<std::string>& in)
{
    std::string ret = "error";
    std::stack<std::string> stack;
    double dat; 
    int i;

    for (i = 0; i < in.size(); i++)
    {
        std::string tmp = in[i];

        if (in[i] == "+" || in[i] == "-" || in[i] == "*" || in[i] == "/")
        {
            std::string r = !stack.empty() ? stack.top() : "";  //top()函数是栈顶元素,这里不能使用pop()函数
            if (!stack.empty())
                stack.pop();                                    //pop函数的返回值为void
            std::string l = !stack.empty() ? stack.top() : "";
            if (!stack.empty())
                stack.pop();
            std::string result = cal(l, in[i], r);

            if (result != "error")
            {
                stack.push(result); 
            }
            else
                break;
        }
        else if (toDouble(tmp, dat))
        {

            stack.push(in[i]);
        }
        else
            break;
    }
    //最后栈中存放最后的运算结果
    if( i == in.size() && (stack.size() == 1) && toDouble(stack.top(), dat) )
    {
        ret = stack.top();
    }

    return ret;
}

int main(void)
{
    calculate c;
    std::vector<std::string> ret;
    std::vector<std::string> out;

    c.split("9 + 2 * 3 + (4 * 5 + 6) * 7", ret);
    //for (int i = 0; i < ret.size(); i++ )
        //std::cout << ret[i] << std::endl; 

    c.transform(ret, out);
    std::cout <<"9 + 2 * 3 + (4 * 5 + 6) * 7 = " << c.cal(out) << std::endl;    

    return 0;
}

  编译运行:
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值