中缀转后缀表达式(leetcode 150 && 224 && 227 && 772)

目录

0) 总结记忆

1)定义

2)后缀表达式求值

3)中缀转后缀

4) 代码

   1) (后缀计算)leetcode 150. 逆波兰表达式求值  

2)中缀转后缀

3) leetcode 224. 基本计算器 &&  227. 基本计算器 II  && 772. 基本计算器 III


0) 总结记忆

1. 后缀计算: 一个栈,遍历字符串,遇到数字,压栈,遇到运算符,栈弹两个计算再压栈。

2. 中缀转后缀: 两个栈,栈1保存中间结果,栈2保存运算符(优先级从低到高),遍历字符串,遇到数字,压栈1,遇到运算符,压栈2,且可能有弹栈操作,弹出的运算符到栈1去。最后栈1逆序输出。

前缀中缀后缀互转

1)定义

中缀表达式就是我们日常写的表达式,如 a+(b-c)*d ,

而后缀表达式则是运算符在操作数后面称为后缀表达式(也称逆波兰表达式),编译系统将中缀表达式改写 abc-d*+ 方便运算。

tips: 中缀转后缀,得到的后缀表达式不唯一,要想验证两个后缀表示式是一致的,把它转回中缀表达式,进行对比。

2)后缀表达式求值

其求值过程可以用到栈来辅助存储。

基本过程:

  • 用一个栈,遍历表达式,遇到数字则压入栈中,遇到运算符则从栈中弹出两个数,并将计算后的结果压回栈中。

比如待求值的后缀表达式为:6  5  2  3  + 8 * + 3  +  *,则其求值过程如下:

1)遍历表达式,遇到数字则压入栈中

2)接着读到“+”,则弹出3和2,执行3+2,计算结果等于5,并将5压入到栈中。

3)读到8,将其直接放入栈中。

4)读到“*”,弹出8和5,执行8*5,并将结果40压入栈中。而后过程类似,读到“+”,将40和5弹出,将40+5的结果45压入栈...以此类推。最后求的值288。

3)中缀转后缀

  1. 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数时,将其压s2;
  4. 遇到运算符时,比较其与s1栈顶运算符的优先级:
  1. 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;

  2. 否则,若优先级比栈顶运算符的高,也将运算符压入s1

  3. 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较。(栈顶与当前优先级相同也弹)

总结就是: 弹出优先级大于等于自己的运算符号。(左括号的优先级最低为0)

     5. 遇到括号时:

              如果是左括号“(”,则直接压入s1;

              如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;

     6.  重复步骤2至5,直到表达式的最右边;

     7.   将s1中剩余的运算符依次弹出并压入s2;

     8.  依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

然而实际代码并不用两个栈,用一个stack 保存 运算符即可,并且考虑到可能一个运算数是两位或两位以上,所以应该用vector<string> 保存后缀结果。

4) 代码

   1) (后缀计算)leetcode 150. 逆波兰表达式求值  

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        
        stack<int> sta;
        for(auto& i:tokens){
            if(i=="+" || i== "-" || i=="*" || i=="/"){
                int res;
                int right=sta.top();
                sta.pop();
                int left=sta.top();
                sta.pop();
                if(i=="+")
                    res=left+right;
                else if(i=="-")
                    res= left-right;
                else if(i=="*")
                    res =left*right;
                else 
                    res= left/right;
                sta.push(res);
            } else
                sta.push(stoi(i));
            
        }
        
        return sta.top();
    }
};

2)中缀转后缀

// 转换str格式 使其满足要求
string strFormat(string str){
	string s;
	
	for(auto i:str){         // 删除空格
		if(i==' ') continue;
		s += i;
	}
	
	string res;

	for(int i=0;i<s.size();++i){      //解决(-1+2)负数报错问题 	
		if(s[i]=='-')				//即在 -1 前面加一个0 变成  0-1 即可
			if(i==0 || s[i-1]=='(')
				res += '0';
		res += s[i];
	}
	
	return res;
	
}


//中缀转后缀
vector<string> toPost(string s){
	stack<char> sta;
	string one;      // 可能是两位数
	vector<string> post;
	for(char& i:s){
		if(i>='0' && i<='9')
			one += i;
		else{
			if(one.size()){
				post.push_back(one);
				one="";
			}
			
			if(i=='(') sta.push(i);
			else if(i==')'){
				while(sta.top()!='('){
					post.push_back(string(1,sta.top()));
					sta.pop();
				}
				sta.pop();
			}
			else if(i=='+' || i=='-'){
				while(sta.size() && sta.top()!='('){
					post.push_back(string(1,sta.top()));
					sta.pop();
				}
				
				sta.push(i);
			}
			
			else if(i=='*' || i=='/'){
				while(sta.size() && (sta.top()=='*' || sta.top() == '/') ){
					post.push_back(string(1,sta.top()));
					sta.pop();
				}
				
				sta.push(i);
			}
				
			
		}
	}
	if(one.size()) post.push_back(one); // 别忘了检查one 可能还有值没存
	while(sta.size()){
		post.push_back(string(1,sta.top()));
		sta.pop();
	}
	
	return post;
}

3) leetcode 224. 基本计算器 &&  227. 基本计算器 II  && 772. 基本计算器 III

记这个!, 直接中缀表达式求值

        中缀表达式求值是通过两个栈来实现的。其中一个保存操作数的栈,另一个是保存运算符的栈。

        我们从左向右遍历表达式,当遇到数字,我们就直接压入操作数栈;当遇到运算符,就与运算符栈的栈顶元素进行比较。

        如果比运算符栈顶元素的优先级高,就将当前运算符压入栈;

        如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取 2 个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续比较。 

        ‘(’ 的优先级最低为0

class Solution {
public:
    int calculate(string s) {
        str_format(s); // 格式化s
        
        stack<int> nums; // 操作数
        stack<char> ops; // 运算符号

        /*

        中缀表达式求值是通过两个栈来实现的。其中一个保存操作数的栈,另一个是保存运算符的栈。
        我们从左向右遍历表达式,当遇到数字,我们就直接压入操作数栈;当遇到运算符,就与运算符栈的栈顶元素进行比较。
        如果比运算符栈顶元素的优先级高,就将当前运算符压入栈;
        如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取 2 个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续比较。 
        ‘(’ 的优先级最低为0
        */

        unordered_map<char, function<int(int, int)>> op_2_calc = {
            {'+', plus<int>()},
            {'-', minus<int>()},
            {'*', [](int num1, int num2){return num1 * num2;}},
            {'/', [](int num1, int num2) {return num1 / num2;}}
        };

        unordered_map<char, int> op_2_priority = {
            {'(', 0},
            {'+', 1},
            {'-', 1},
            {'*', 2},
            {'/', 2},
        };

        for (int i = 0; i < s.size(); i++)
        {
            char c = s[i];
            if (c <= '9' && c >= '0')
            {
                int one = 0;
                while (i < s.size() && isdigit(s[i]))
                {
                    one  = one * 10 + (s[i] - '0');
                    ++i;
                }
                --i;
                nums.push(one);
                
            } else if (op_2_calc.count(c)) {
                while (ops.size() && op_2_priority[c] <= op_2_priority[ops.top()]){
                    int num2 = nums.top();
                    nums.pop();
                    int num1 = nums.top();
                    nums.pop();
                    nums.push(op_2_calc[ops.top()](num1, num2));
                    ops.pop();
                }
                ops.push(c);
            } else if (c == '(') {
                ops.push(c);
            } else if (c == ')') {
                while (ops.size() && ops.top() != '(')
                {
                    int num2 = nums.top();
                    nums.pop();
                    int num1 = nums.top();
                    nums.pop();
                    nums.push(op_2_calc[ops.top()](num1, num2));
                    ops.pop();
                }
                ops.pop();
            }
        }
        return nums.top();
    }

    void str_format(string& s)
    {
        string t = "("; // 首尾加 () 保证会被计算
        
        /*
         1. 删除空格
         2. 对于 -1 + 2 或者 +1 + 2  这种+ -号不是表示运算符 而是表示正负号的,变为 0-1+2
        */
        for (char c: s){
            if (c == ' ') 
                continue;
            else if ((c == '+' || c == '-') && (t.back() == '(')) {
                t += '0';
                t += c;
            } else {
                t += c;
            }
        }
        t += ')';
        s = t;
        return;
    }

    


};

class Solution {
public:
	using LL=long long;  // 用int  772题 会溢出
    LL calculate(string s) {
        string str=strFormat(s);
        vector<string> vec=toPost(str);
        LL res = evalRPN(vec);
        return res;
    }
    
// 转换str格式 使其满足要求
string strFormat(string str){
	string s;
	
	for(auto i:str){         // 删除空格
		if(i==' ') continue;
		s += i;
	}
	
	string res;

	for(LL i=0;i<s.size();++i){      //解决(-1+2)负数报错问题 	
		if(s[i]=='-')				//即在 -1 前面加一个0 变成  0-1 即可
			if(i==0 || s[i-1]=='(')
				res += '0';
		res += s[i];
	}
	
	return res;
	
}


//中缀转后缀
vector<string> toPost(string s){
	stack<char> sta;
	string one;        // 可能是两位数
	vector<string> post;
	for(char& i:s){
		if(i>='0' && i<='9')
			one += i;
		else{
			if(one.size()){
				post.push_back(one);  // one 有值就加进去
				one="";
			}
			
			if(i=='(') sta.push(i);
			else if(i==')'){
				while(sta.top()!='('){
					post.push_back(string(1,sta.top()));  // 不能直接用sta.top 因为 post放的是string,而sta存的是char
					sta.pop();
				}
				sta.pop();
			}
			else if(i=='+' || i=='-'){
				while(sta.size() && sta.top()!='('){
					post.push_back(string(1,sta.top()));
					sta.pop();
				}
				
				sta.push(i);
			}
			
			else if(i=='*' || i=='/'){
				while(sta.size() && (sta.top()=='*' || sta.top() == '/') ){
					post.push_back(string(1,sta.top()));
					sta.pop();
				}
				
				sta.push(i);
			}
				
			
		}
	}
	if(one.size()) post.push_back(one);       // 别忘了检查one 可能还有值没存
	while(sta.size()){
		post.push_back(string(1,sta.top()));
		sta.pop();
	}
	
	return post;
}


// 后缀计算

LL evalRPN(vector<string>& tokens) {
	
	stack<long long > sta;
	for(auto& i:tokens){
		if(i=="+" || i== "-" || i=="*" || i=="/"){
			LL res;
			LL right=sta.top();
			sta.pop();
			LL left=sta.top();
			sta.pop();
			if(i=="+")
				res=left+right;
			else if(i=="-")
				res= left-right;
			else if(i=="*")
				res =left*right;
			else 
				res= left/right;
			sta.push(res);
		} else
			sta.push(stoll(i));
		
	}
	
	return sta.top();
}
    
    
};

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
中缀后缀表达式是一种将数学表达式从中缀形式换为后缀形式的方法。下面我以一个简单的数学表达式"c"为例来说明中缀后缀的过程。 在中缀后缀的过程中,我们需要使用一个栈来辅助操作。具体的步骤如下: 1. 创建一个空栈和一个空字符串,分别用来存储运算符和后缀表达式。 2. 从左到右遍历中缀表达式。对于每个元素,进行如下操作: - 如果当前元素是操作数(即字母或数字),则直接将其添加到后缀表达式中。 - 如果当前元素是运算符,则进行如下操作: - 如果栈为空,或栈顶元素为左括号"(",则将当前运算符入栈。 - 如果当前运算符的优先级大于栈顶运算符的优先级,则将当前运算符入栈。 - 如果当前运算符的优先级小于或等于栈顶运算符的优先级,则将栈顶运算符出栈,并添加到后缀表达式中。重复此步骤,直到当前运算符的优先级大于栈顶运算符的优先级为止。最后,将当前运算符入栈。 - 如果当前元素是左括号"(",则将其入栈。 - 如果当前元素是右括号")",则将栈中的元素出栈,并添加到后缀表达式中,直到遇到左括号"("为止。此时,将左括号出栈。 3. 当中缀表达式遍历完毕后,将栈中剩余的运算符依次出栈,并添加到后缀表达式中。 最后,输出得到的后缀表达式即为"c"。 需要注意的是,中缀后缀算法中还涉及到对运算符优先级的处理,不同运算符具有不同的优先级,根据具体的运算符优先级规则进行处理。同时,也需要考虑到括号的影响,所以在遍历过程中需要根据遇到的括号进行相应的处理操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值