波兰表达式 与 逆波兰表达式

逆波兰表达式       

        逆波兰表达式(Reverse Polish Notation,RPN),又称为后缀表达式,是一种特殊的算术表达式形式。

一、定义与起源

  • 定义:逆波兰表达式是一种将运算符写在运算量(操作数)后面的表达式形式。
  • 起源:该表达式形式由波兰逻辑学家J・卢卡西维兹(J・ Lukasiewicz)于1929年首先提出。

二、特点与结构

  • 运算顺序:逆波兰表达式严格遵循从左到右的运算顺序,无需括号来指明运算的优先级。
  • 运算符位置:与常规的中缀表达式(即运算符位于两个运算量之间)不同,逆波兰表达式的运算符位于其操作数的后面。
  • 运算量:可以是整数、变量,也可以是另一个逆波兰表达式。

三、运算过程

  • 入栈与出栈:逆波兰表达式的计算通常通过栈(Stack)数据结构来实现。当遇到运算量时,将其压入栈中;当遇到运算符时,从栈中弹出两个运算量(即栈顶的两个元素),根据运算符进行相应的运算,然后将结果再压入栈中。
  • 最终结果:当表达式扫描完毕后,栈中剩下的元素即为最终的计算结果。

四、优势与应用

  • 优势:逆波兰表达式的优势在于其简洁的运算过程和易于实现的计算机算法。由于无需括号来指明运算优先级,因此减少了表达式的复杂性。
  • 应用:逆波兰表达式在计算机科学中有广泛应用,如编译器设计、算术表达式求值、逻辑电路设计等。此外,日本的福岛先生最早将逆波兰表达式应用于情报检索,故又称为“福岛方法”。

五、示例

以中缀表达式“(a+b)*(c+d)”为例,其逆波兰表达式为“ab+cd+*”。具体转换过程如下:

  1. 扫描到“(a+b)”,将其转换为逆波兰形式“ab+”并压入栈中(但在此例中,我们直接给出转换结果,实际转换过程可能涉及更复杂的算法)。
  2. 扫描到“*(c+d)”,先将“c+d”转换为逆波兰形式“cd+”,然后与栈顶的“ab+”进行乘法运算(即弹出“ab+”和“cd+”,计算“(ab+)(cd+)”并压入结果)。
  3. 最终得到逆波兰表达式“ab+cd+*”。

六、代码示例

        150. 逆波兰表达式求值 - 力扣(LeetCode)

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> number;
        int right, left;
        for (auto it : tokens)
        {
            if (isdigit(it.back()))
            {
                number.push(stoi(it.c_str()));
            }
            else
            {
                right = number.top();
                number.pop();
                left = number.top();
                number.pop();
                switch (it[0])
                {
                case '+':
                    number.push(right + left);
                    break;
                case '-':
                    number.push(left - right);
                    break;
                case '*':
                    number.push(right * left);
                    break;
                case '/':
                    number.push(left / right);
                    break;
                }
            }
        }
        return number.top();
    }
};

 波兰表达式

        波兰表达式,也被称为前缀表达式,是一种数学表达式的表示方法。它由波兰逻辑学家J.Lukasiewicz于1929年提出,旨在简化逻辑学和数学中表达式的描述和处理。

一、定义与特点

  • 定义:波兰表达式是一种将操作符放在操作数之前的表达方式。
  • 特点:在波兰表达式中,运算符必须位于操作数之前,且由于操作符的位置决定了计算的顺序,因此这种表达式不需要括号来指示运算的优先级。

二、与其他表达式的比较

  • 中缀表达式:这是最常见的数学表达式形式,运算符位于两个操作数之间。中缀表达式直观易懂,但在计算时需要考虑运算符的优先级和括号的存在。
  • 后缀表达式:也称为逆波兰表达式,将运算符放在操作数之后。同样不需要括号来指示运算顺序,计算时从左到右进行。

与中缀表达式相比,波兰表达式和后缀表达式的好处在于没有括号,因此在计算时无需考虑优先级,这能够提高计算机的运算效率。

三、计算与转换

  • 计算:在计算波兰表达式时,通常从右到左遍历表达式,根据运算符和操作数的位置进行计算。
  • 转换:中缀表达式可以转换为波兰表达式。转换过程通常涉及使用栈来处理运算符的优先级。具体地,将中缀表达式依据优先级关系括起来,然后将运算符移到对应括号的前方(对于波兰表达式)或后方(对于后缀表达式),最后去掉括号。

四、中缀表达式与后缀表达式的转换

        1.建立一个栈

        2.遇到运算符,如果栈为空或当前运算符高于栈顶运算符优先级,入栈

        3.遇到运算符,如果栈不为空且当前运算符低于或等于栈顶运算符优先级,出栈

        4.结束时,全部出栈

题目 224. 基本计算器 - 力扣(LeetCode)  

        思路A(不去括号采用递归)
class Solution {
public:
        void toRPN(const string& s, size_t& i, vector<string>& v)
    {
        stack<char> st;
        while (i < s.size())
        {
            if (isdigit(s[i]))
            {
                string num;
                while (i < s.size() && isdigit(s[i]))
                {
                    num += s[i];
                    i++;
                }
                v.push_back(num);
            }
            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() || ((s[i] == '*' || s[i] == '/') && (st.top() != '*' || st.top() != '/')))
                {
                    st.push(s[i++]);
                }
                else
                {
                    v.push_back(string(1, st.top()));
                    st.pop();
                }
            }
        }
        while (!st.empty())
        {
            v.push_back(string(1, st.top()));
            st.pop();
        }
    }

    int evalRPN(vector<string>& tokens) {
        stack<int> number;
        int right, left;
        for (auto it : tokens)
        {
            if (isdigit(it.back()))
            {
                number.push(stoi(it.c_str()));
            }
            else
            {
                right = number.top();
                number.pop();
                left = number.top();
                number.pop();
                switch (it[0])
                {
                case '+':
                    number.push(right + left);
                    break;
                case '-':
                    number.push(left - right);
                    break;
                case '*':
                    number.push(right * left);
                    break;
                case '/':
                    number.push(left / right);
                    break;
                }
            }
        }
        return number.top();
    }
    int calculate(string s) {
        size_t i = 0;vector<string> v;
        string ne;
        //去空格
        
        for (auto it : s)
        {
            if (it != ' ')
                ne.push_back(it);
        }
        
        s.clear();
        //去负数
        
        for (int n = 0; n < ne.size(); n++)
        {
            if (ne[n] == '-' && ( n == 0 ||(!isdigit(ne[n-1])&&s[n-1] != ')')))
            {
                s += "0-";
            }
            else
            {
                s.push_back(ne[n]);
            }
        }
        
        
        toRPN(s, i, v);
        for (auto& e : s)
        {
        cout << e << " ";
        }

        return evalRPN(v);
    }
};
        思路B(直接去括号不要递归)

 思路很简单 把括号内的 + 变 - -变+ 即可 不需要递归了

        思路C(不需要变换)

因为中值表达式 可以在思路B的基础上 不进行变换 直接进行优先级运算

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值