逆波兰表达式

目录

1. 概念

2. 中缀表达式转换为后缀表达式

isdigit函数

运算符优先级比较

 代码实现

3. 力扣 150 逆波兰表达式求值

 stoi函数

具体思路

代码

4. 力扣224 基本计算器

逻辑细节

代码实现


1. 概念

逆波兰表达式,也称为后缀表达式在这种表达式中所有的操作符置于操作数的后面。这种表达式格式特别适合用于计算机程序的算数运算,因为他能避免使用括号来标识操作符的优先级,从而简化计算过程。

2. 中缀表达式转换为后缀表达式

依次读取计算表达式中的值,遇到运算数直接输出(或存储起来)。

建立一个栈来存储运算符,利用栈后进先出的性质,在遇到后面运算符时出栈里面存储的前面的运算符进行比较,确定优先级。

(1) 遇到运算符,如果栈为空或者栈不为空且当前运算符比栈运算符优先级高,则当前运算符入栈。因为如果栈里面存储的是前一个运算符,当前运算符比前一个优先级高,说明前一个不能运算,当前运算符也不能运算,因为后面可能有更高优先级的运算符。

(2) 遇到运算符,如果栈不为空且当前运算符比栈顶运算符优先级低或相等,说明栈顶的运算符可以运算了,输出(存储)栈顶运算符,当前运算符继续走前面遇到运算符的逻辑进行判断

如果遇到() 则把括号的计算表达式当成一个子表达式,进行递归处理子表达式,处理后转换出的后缀表达式加载前面表达式的后面输出(或存储)即可

输出栈中剩余的所有运算符。

isdigit函数

此处为了方便先介绍一个库函数isdigit()

此函数用来检查一个字符是否为数字,是 返回true,不是 返回false

在其他语言中功能或有差异例如python中是检测字符串是否为数字,此处不过多赘述

运算符优先级比较

运算符'+'  '-'   '*'   '/'  的优先级显然不可以直接根据ASCII值进行比较

可通过结构体来设置一个结构体数组,再通过函数进行比较

	struct Priority
	{
		char _op;
		int _bp;
	};
	Priority p[]= { {'+',1},{'-',1},{'*',2},{'/',2} };

或者直接通过map进行更方便的比较()

map<char, int> OperatorPriority = { {'+',1},{'-',1},{'*',2},{'/',2} };
 代码实现

其中函数toRPN的第二个参数为了方便递归,第三的是为了方便下面的题目

map<char, int> OperatorPriority = { {'+',1},{'-',1},{'*',2},{'/',2} };
class conversion
{
public:

	//中缀表达式转后缀表达式
	void toRPN(const string& s, size_t& i, vector<string>& v)
	{
		stack<char> st;
		while (i < s.size())
		{
			if (isdigit(s[i]))//isdigit:若是数字0到九就返回true
			{
				string tmp;
				while (i < s.size() && isdigit(s[i]))
				{
					tmp += s[i];
					i++;
				}
				v.push_back(tmp);
			}
			else
			{
				if (s[i] == '(')
				{
					i++;
					toRPN(s, i, v);
				}

				else if (s[i] == ')')
				{
					while (!st.empty())
					{
						v.push_back(string(1, st.top()));
						st.pop();
					}
					i++;
					return;
				}
				else if (st.empty() || OperatorPriority[s[i]] > OperatorPriority[st.top()])//在上面两个判断下,不然(或)就会入栈
				{
					st.push(s[i]);
					i++;
				}
				else
				{
					v.push_back(string(1, st.top()));
					st.pop();
				}
			}
		}
		while (!st.empty())
		{
			v.push_back(string(1, st.top()));
			st.pop();
		}
	}

};

3. 力扣 150 逆波兰表达式求值

题目介绍:

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意事项:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。
 stoi函数

我们先简单介绍一下stoi来方便我们解题

stoi是C++标准库里的一个函数,主要作用是将字符串转换为整数,可以处理不同进制的数字字符串,并将其转换为十进制的整数。

stoi 函数的原型如下:

int  stoi(const std::string& str ,  std::size_t* pos = nullptr ,  int base = 10);

其中

1. str 是要转换的字符串。

2. pos 是一个指向 size_t 的指针,用于存储转换停止的位置。如果不需要这个信息,可以设置为 nullptr。

3. base 表示字符串中数字的进制,默认是 10 进制。如果设置为 0,进制会根据字符串的格式自动判断。

 其余先不作说明。

具体思路

整体很简单,1. 我们先建立一个栈来存储整数

2. 遇到操作符我们就出掉栈里的两个元素

3. 让其进行对应的运算符操作后再进栈

4. 直到数组走完,此时栈顶就是最后的值,返回栈顶元素即可

代码
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for(auto e:tokens)
        {

            if(!(e=="+"||e=="-"||e=="*"||e=="/"))
            {
                st.push(stoi(e));//stoi//将字符串转化为整数
            }
            else
            {
                int sum1=st.top();
                st.pop();
                int sum2=st.top();
                st.pop();
                    if(e=="+")
                    {
                        st.push(sum1+sum2);
                    }
                    else if(e=="-")
                    {
                        st.push(sum2-sum1);
                    }
                    else if(e=="*")
                    {
                        st.push(sum2*sum1);
                    }
                    else if(e=="/")
                    {
                        st.push(sum2/sum1);
                    }
                }
        }
        return st.top();
    }
};

4. 力扣224 基本计算器

题目介绍

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

示例 1:

输入:s = "1 + 1"
输出:2

示例 2:

输入:s = " 2-1 + 2 "
输出:3

示例 3:

输入:s = "(1+(4+5+2)-3)+(6+8)"
输出:23

我们将前两个的代码先粘贴到此题后

逻辑细节

根据示例我们发现,给定的字符串有空格,我们上面的代码无法处理空格,于是我们可以新建一个字符串接收给定字符串的值,遇到' '就不接收,就可以得到一个无空格的表达式

        string news;
        for(auto e:s)
        {
            if(e!=' ')
            news+=e;
        }

此时我们发现

有负号我们就无法处理了,我们可以在中缀转后缀那里更改,但是逻辑有一些麻烦。

所以我们可以将负号'-'转换为"0-"来加入到字符串中,什么时候'-'是负号呢

假如当前s[i] 是字符 '-'

1. '-' 前面的一位 s[i-1]不能是数字

2. '-' 前面的一位 s[i-1]不能是字符')' 

3. 当 '-' 处于s[0] 处即i==0,前面不可能有字符了,是负号

 判断逻辑如下,news为新字符串

if(s[i]=='-'&&(i==0||(!isdigit(s[i-1])&&s[i-1]!=')')))
            {
                news+="0-";              
            }
            else{
                news+=s[i];
            }
代码实现
static map<char, int> OperatorPriority = { {'+',1},{'-',1},{'*',2},{'/',2} };
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for (auto e : tokens) {

            if (!(e == "+" || e == "-" || e == "*" || e == "/")) {
                {
                    cout<<e;
                    st.push(stoi(e));
                } // stoi//将字符串转化为整数
            } else {
                int sum1 = st.top();
                st.pop();
                int sum2 = st.top();
                st.pop();
                if (e == "+") {
                    st.push(sum1 + sum2);
                } else if (e == "-") {
                    st.push(sum2 - sum1);
                } else if (e == "*") {
                    st.push(sum2 * sum1);
                } else if (e == "/") {
                    st.push(sum2 / sum1);
                }
            }
        }
        return st.top();
    }
    struct priority {
        char _op;
        int _pd;
    };

int operatorpriority(char c)
	{
	struct priority
	{
		char _op;
		int _pd;

	};
	static priority p[] = { {'+',1},{'-',1},{'*',2},{'/',2} };
		for (auto e : p)
		{
			if (e._op == c)
			{
				return e._pd;
			}
		}

		return -1;
	}

//static map<char, int> OperatorPriority = { {'+',1},{'-',1},{'*',2},{'/',2} };//不能在这,不然需要将类实例化
class conversion
{
public:

	//中缀表达式转后缀表达式
	void toRPN(const string& s, size_t& i, vector<string>& v)
	{
		stack<char> st;
		while (i < s.size())
		{
			if (isdigit(s[i]))//isdigit:若是数字0到九就返回true
			{
				string tmp;
				while (i < s.size() && isdigit(s[i]))
				{
					tmp += s[i];
					i++;
				}
				v.push_back(tmp);
			}
			else
			{
				if (s[i] == '(')
				{
					i++;
					toRPN(s, i, v);
				}
                else if (s[i] == ')')
				{
					while (!st.empty())
					{
						v.push_back(string(1, st.top()));
						st.pop();
					}
                    i++;
                    return ;
				}
				else if (st.empty() || OperatorPriority[s[i]] > OperatorPriority[st.top()])//在上面两个判断下,不然(或)就会入栈
				{
					st.push(s[i]);
					i++;
				}

				else
				{
					v.push_back(string(1, st.top()));
					st.pop();
				}
			}
		}
		while (!st.empty())
		{
			v.push_back(string(1, st.top()));
			st.pop();
		}
	}

};
    int calculate(string s)
     {
        string news;
        for(auto e:s)
        {
            if(e!=' ')
            news+=e;
        }

        s.swap(news);
        news.clear();

     
        for(size_t i=0;i<s.size();i++)
        {
            if(s[i]=='-'&&(i==0||(!isdigit(s[i-1])&&s[i-1]!=')')))
            {
                news+="0-";              
            }
            else{
                news+=s[i];
            }
        } 
        vector<string> v;
        conversion c;
        size_t i=0;
        c.toRPN(news,i,v);
        
        return evalRPN(v);
     }
};

这篇就到这里啦(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

ヾ( ̄▽ ̄)Bye~Bye~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值