栈的使用场景之一,中缀表达式转为后缀表达式。
后缀表达式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,从左向右进行,转为后缀表达式后,将可以不再考虑运算符的优先规则,显然这才符合计算机的思维。
将中缀表达式拆分成各个数字和运算符,并去除了括号,存到数组(或者容器、队列)中,遍历之:
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;
}
编译运行: