背景
网上找了一圈没有现成的逻辑运算的中缀表达式转后缀表达式,全是四则运算的,自己写一下。
代码
#include<iostream>
#include<stack>
#include<queue>
#include<map>
#include<string>
#include<cstdio>
#include<sstream>
#include <iostream>
using namespace std;
enum NodeType
{
TypeDIGIT,//数字
TypeBOOLEN,//bool
TypeOP//运算符
};
struct Node{
std::string content;//
NodeType type;
};
typedef struct Node node;
class Parser
{
private:
//设置优先级(注意默认操作数的优先级最高,即其不需要进栈,进栈的都是运算符)
map<std::string, int> p;
//获得从 str 的index位置获得 bool 字符串
bool getBool(const std::string& str,int index,std::string&bl)
{
bl.clear();
if(index+4>str.length())
{
return false;
}
bl=str.substr(index,4);
if(bl=="true")
{
return true;
}
if(index+5>str.length())
{
return false;
}
bl=str.substr(index,5);
if(bl=="false")
{
return true;
}
return false;
}
//获得从 str 的index位置获得 数字 字符串
bool getDigit(const std::string& str,int index,std::string&digit)
{
digit.clear();
while(index<str.size()&&isDigit(str[index]))
{
digit+=str[index];
index++;
}
if(digit.empty())
{
return false;
}
else
{
return true;
}
}
//获得从 str 的index位置获得 操作符 字符串
bool getOp(const std::string& str,int index,std::string&op)
{
char current_char=str[index];
if (current_char == '=') {
char next_char=str.size()>(index+1)?str[index+1]:0;
if(next_char == '=')
{
op="==";
}else
{
return false;
}
}
if (current_char == '!') {
char next_char=str.size()>(index+1)?str[index+1]:0;
if(next_char == '=')
{
op="!=";
}
else
{
op="!";
}
}
if (current_char == '<') {
char next_char=str.size()>(index+1)?str[index+1]:0;
if(next_char == '=')
{
op="<=";
}
else
{
op="<";
}
}
if (current_char == '>') {
char next_char=str.size()>(index+1)?str[index+1]:0;
if(next_char == '=')
{
op="<=";
}
else
{
op=">";
}
}
if (current_char == '&') {
char next_char=str.size()>(index+1)?str[index+1]:0;
if(next_char == '&')
{
op="&&";
}
else
{
return false;
}
}
if (current_char == '|') {
char next_char=str.size()>(index+1)?str[index+1]:0;
if(next_char == '|')
{
op="||";
}
else
{
return false;
}
}
return true;
}
bool calcEQ(const std::string &a,const std::string & b)
{
return std::stoi(a)==std::stoi(b);
}
bool calcNE(const std::string &a,const std::string & b)
{
return std::stoi(a)!=std::stoi(b);
}
bool calcLT(const std::string &a,const std::string & b)
{
return std::stoi(a)<std::stoi(b);
}
bool calcGT(const std::string &a,const std::string & b)
{
return std::stoi(a)>std::stoi(b);
}
bool calcLE(const std::string &a,const std::string & b)
{
return std::stoi(a)<=std::stoi(b);
}
bool calcGE(const std::string &a,const std::string & b)
{
return std::stoi(a)>=std::stoi(b);
}
bool toBool(const std::string & b)
{
bool v;
std::istringstream(b) >> std::boolalpha >> v;
return v;
}
bool calcNOT(const std::string & b)
{
return !toBool(b);
}
std::string toString(bool b)
{
if(b)
{
return "true";
}else
{
return "false";
}
}
bool isDigit(char c) {
if (c >= '0' && c <= '9')
return true;
return false;
}
public:
Parser()
{
p["&&"] = p["||"] = 1;//通过hashmap赋值
p[">"] = p[">="]=p["<"] = p["<="]=p["=="] = p["!="] = 2;//通过hashmap赋值
p["!"] = 3;//通过hashmap赋值
}
/*
中缀转后缀C++代码实现(比较方便)
1.遇到操作数:添加到后缀表达式中或直接输出
2.栈空时:遇到运算符,直接入栈
3.遇到左括号:将其入栈
4.遇到右括号:执行出栈操作,输出到后缀表达式,直到弹出的是左括号
注意:左括号不输出到后缀表达式
5.遇到其他运算符:弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;栈顶左括号,将该运算符入栈
6.将栈中剩余内容依次弹出后缀表达式
*/
queue<node> change(const std::string& str){
stack<node> s;//操作符栈
queue<node> q;//后缀表达式队列
string var;
for (int i = 0; i < str.length();){
if (str[i] == '('){//3.遇到左括号:将其入栈
node temp;
temp.type = TypeOP;
temp.content = str[i];
s.push(temp);
i++;
}
else if (str[i] == ')'){//4.遇到右括号:执行出栈操作,输出到后缀表达式,直到弹出的是左括号
while (!s.empty() && s.top().content != "("){
q.push(s.top());
s.pop();
}
s.pop();//弹出左括号
i++;
}
else if (getDigit(str,i,var)){
//如果是数字
node temp;
temp.type = TypeDIGIT;
temp.content = var ;
i+=var.length();
q.push(temp);//操作数进入后缀表达式
}
else if (getBool(str,i,var)){
//如果是
node temp;
temp.type = TypeBOOLEN;
temp.content = var ;
i+=var.length();
q.push(temp);//操作数进入后缀表达式
}
else if(getOp(str,i,var)){
//如果是操作符
//5.遇到其他运算符:弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;栈顶左括号,将该运算符入栈
node temp;
temp.type = TypeOP;
if(s.size()==0||s.top().content=="(")
{
}
else{
while (!s.empty() && p[s.top().content] >= p[var]){
q.push(s.top());
s.pop();
}
}
temp.content = var;
s.push(temp);
i+=var.length();
}else
{
return q;
}
}
//6.将栈中剩余内容依次弹出后缀表达式
while (!s.empty()){
q.push(s.top());
s.pop();
}
return q;
}
//*************************************************************
//后缀表达式的计算
/*
从左到右扫描后缀表达式
1)若是操作数,就压栈,
2)若是操作符,就连续弹出两个操组数
3)栈顶的值即为所需结果
注:先弹出的是第一操作数,后弹出的是第二操作数
*/
bool calculate( queue<node>& q ){
stack<node> s1;//存放操作数的,为了计算后缀表达式的值
node cur, temp;
while (!q.empty()){//后缀队列非空
cur = q.front();//记录队首元素
q.pop();
if (cur.type == TypeBOOLEN||cur.type ==TypeDIGIT){//是操作数进入栈
s1.push(cur);
}
else{//是操作符就运算
std::string var_a,var_b;
if(cur.content == "!")
{
var_b =s1.top().content;
s1.pop();//弹出第二操作数
temp.type = TypeBOOLEN;
temp.content=toString(!toBool(var_b));
}else
{
var_b =s1.top().content;
s1.pop();//弹出第二操作数
var_a = s1.top().content;
s1.pop();//弹出第一操作数
temp.type = TypeBOOLEN;
if (cur.content == "=="){
temp.content = toString(calcEQ(var_a , var_b));
}
else if (cur.content == "!="){
temp.content = toString(calcNE(var_a , var_b));
}
else if (cur.content == "<="){
temp.content = toString(calcLE(var_a , var_b));
}
else if (cur.content == "<"){
temp.content = toString(calcLT(var_a , var_b));
}else if (cur.content == ">="){
temp.content = toString(calcGE(var_a , var_b));
}
else if (cur.content == ">"){
temp.content = toString(calcGT(var_a , var_b));
}
else if (cur.content == "&&"){
temp.content = toString(toBool( var_a) && toBool(var_b));
}
else if (cur.content == "||"){
temp.content = toString(toBool(var_a) || toBool(var_b));
}
}
s1.push(temp);//把计算后的结果再次压栈
}
}
return toBool(s1.top().content);
}
//*************************************************************
};
int main()
{
Parser p;
//queue<Node> q=p.change("!false");
queue<Node> q=p.change("12<23&&!(11>22||13<12)");
bool answer=p.calculate(q);
cout << answer<<endl;
return 0;
}
参考
https://blog.csdn.net/qq_36144258/article/details/95075064
https://blog.csdn.net/Coder_Dacyuan/article/details/79941743