Démonstration animée d'application de pile : Calcul d'expression Visualisez votre code avec des animations

图码-数据结构可视化动画版

编写一个程序将 Infix 表达式转换为 Postfix 形式。

中缀表达式: “a 运算符 b”(a + b) 形式的表达式,即当运算符位于每对操作数之间时。
后缀表达式: “ab 运算符”(ab+) 形式的表达式,即每对操作数后面都跟有一个运算符。

例子:

输入: A + B * C + D
输出: ABC*+D+

输入: ((A + B) – C * (D / E)) + F
输出: AB+CDE/*-F+  

为什么用后缀表示表达式?  

编译器从左到右或从右到左扫描表达式。 
考虑表达式: a + b * c + d

  • 编译器首先扫描表达式以计算表达式 b * c,然后再次扫描表达式以向其添加 a。 
  • 然后在另一次扫描后将结果添加到 d 中。 

重复扫描使得效率非常低。 中缀表达式很容易被人类读取和求解,而计算机无法轻松地区分运算符和括号,因此,最好在计算之前将表达式转换为后缀(或前缀)形式。

后缀形式对应的表达式是 abc*+d+ 可以使用堆栈轻松计算后缀表达式。 

如何将中缀表达式转换为后缀表达式?

要将中缀表达式转换为后缀表达式,请使用 堆栈数据结构 从左到右扫描中缀表达式。 每当我们得到一个操作数时,将其添加到后缀表达式中,如果我们得到一个运算符或括号,则通过保持其优先级将其添加到堆栈中。

下面是实现上述想法的步骤:

  1. 从左到右 扫描中缀表达式 。 
  2. 如果扫描到的字符是操作数,则将其放入后缀表达式中。 
  3. 否则,请执行以下操作
    • 如果扫描到的运算符的优先级和结合性大于栈中运算符的优先级和结合性[或者栈为空或栈中包含'('],则将其压入栈中。[' ^ ' 运算 符是右关联的,而其他运算符如“ + ”、“ - ”、“ * ”和“ / ”是左关联]。
      • 特别检查堆栈顶部的运算符和扫描的运算符均为“ ^ ”时的情况。 在这种情况下,由于其右结合性,扫描运算符的优先级较高。 所以它会被压入操作符栈。 
      • 在所有其他情况下,当运算符堆栈的顶部与扫描的运算符相同时,则从堆栈中弹出该运算符,因为左关联性导致扫描的运算符具有较低的优先级。 
    • 否则,从堆栈中弹出所有优先级大于或等于扫描到的运算符的运算符。
      • 完成此操作后,将扫描的运算符推入堆栈。 (如果在弹出时遇到括号,则停在那里并将扫描的运算符推入堆栈。) 
  4. 如果扫描到的字符是' ( ',则将其压入堆栈。 
  5. 如果扫描到的字符是' ) ',则出栈并输出,直到遇到' ( ',并丢弃两个括号。 
  6. 重复步骤 2-5 ,直到扫描到中缀表达式。 
  7. 扫描结束后,弹出堆栈并添加后缀表达式中的运算符,直到不为空。
  8. 最后,打印后缀表达式。

插图:

请按照下图更好地理解

考虑中缀表达式 exp = “a+b*c+d”并使用迭代器 i
扫描中缀表达式 ,迭代器初始化为 i = 0

第一步: 这里 i = 0 且 exp[i] = 'a' 即操作数。 所以将其添加到后缀表达式中。 因此, postfix =“a”

在后缀中添加“a”

在后缀中添加“a”

第二步: 这里 i = 1 且 exp[i] = '+' 即运算符。 将其推入堆栈。 postfix = “a” stack = {+}

将“+”压入堆栈

将“+”压入堆栈

第三步: 现在 i = 2 且 exp[i] = 'b' 即操作数。 所以将其添加到后缀表达式中。 后缀 = “ab” 堆栈 = {+}

在后缀中添加“b”

在后缀中添加“b”

第四步: 现在 i = 3 且 exp[i] = '*' 即一个运算符。 将其推入堆栈。 postfix = “ab” stack = {+, *}

将“*”压入堆栈

将“*”压入堆栈

第五步: 现在 i = 4 且 exp[i] = 'c' 即操作数。 将其添加到后缀表达式中。 postfix = “abc” stack = {+, *}

在后缀中添加“c”

在后缀中添加“c”

第六步: 现在 i = 5 且 exp[i] = '+' 即一个运算符。 堆栈最顶层的元素具有更高的优先级。 因此弹出直到堆栈变空或顶部元素的优先级较低。 '*' 被弹出并添加到后缀中。 所以 postfix = “abc*” stack = {+} 。 

弹出“*”并添加后缀

弹出“*”并添加后缀

现在顶部元素是“ + ”,它的优先级也没有降低。 弹出它。 后缀=“abc*+” 。 

弹出“+”并将其添加到后缀中

弹出“+”并将其添加到后缀中

现在堆栈是空的。 因此将 “+” 压入堆栈。 堆栈= {+}

将“+”压入堆栈

将“+”压入堆栈

第七步: 现在 i = 6 且 exp[i] = 'd' 即操作数。 将其添加到后缀表达式中。 后缀=“abc*+d”

在后缀中添加“d”

在后缀中添加“d”

最后一步: 现在没有留下任何元素。 因此清空堆栈并将其添加到后缀表达式中。 后缀=“abc*+d+”

弹出“+”并将其添加到后缀中

弹出“+”并将其添加到后缀中

下面是上述算法的实现: 

C++14

// C++ code to convert infix expression to postfix
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to return precedence of operators
int prec(char c)
{
    if (c == '^')
        return 3;
    else if (c == '/' || c == '*')
        return 2;
    else if (c == '+' || c == '-')
        return 1;
    else
        return -1;
}
 
// The main function to convert infix expression
// to postfix expression
void infixToPostfix(string s)
{
 
    stack<char> st;
    string result;
 
    for (int i = 0; i < s.length(); i++) {
        char c = s[i];
 
        // If the scanned character is
        // an operand, add it to output string.
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
            || (c >= '0' && c <= '9'))
            result += c;
 
        // If the scanned character is an
        // ‘(‘, push it to the stack.
        else if (c == '(')
            st.push('(');
 
        // If the scanned character is an ‘)’,
        // pop and add to output string from the stack
        // until an ‘(‘ is encountered.
        else if (c == ')') {
            while (st.top() != '(') {
                result += st.top();
                st.pop();
            }
            st.pop();
        }
 
        // If an operator is scanned
        else {
            while (!st.empty()
                   && prec(s[i]) <= prec(st.top())) {
                result += st.top();
                st.pop();
            }
            st.push(c);
        }
    }
 
    // Pop all the remaining elements from the stack
    while (!st.empty()) {
        result += st.top();
        st.pop();
    }
 
    cout << result << endl;
}
 
// Driver code
int main()
{
    string exp = "a+b*(c^d-e)^(f+g*h)-i";
 
    // Function call
    infixToPostfix(exp);
   
    return 0;
}


          

C

Java

Python3

C#

Javascript

输出

abcd^e-fgh*+^*+i-

时间复杂度: O(N),其中 N 是中缀表达式的大小
辅助空间: O(N),其中 N 是中缀表达式的大小

如果您发现任何不正确的内容,或者您​​想分享有关上述主题的更多信息,请发表评论。 

给定一个中缀表达式,任务是将其转换为前缀表达式。

中缀表达式: a '运算符' b 类型的表达式 (a+b,其中 + 是运算符),即当运算符位于两个操作数之间时。

前缀表达式: “ 运算符”ab 类型的表达式 (+ab,其中 + 是运算符),即当运算符置于操作数之前时。

例子: 

输入: A*B+C/D
输出: +*AB/CD 

输入: (A – B/C) * (A/KL)
输出: *-A/BC-/AKL

如何将中缀表达式转换为前缀表达式?

要将中缀表达式转换为前缀表达式,我们可以使用 堆栈数据结构 想法如下:

  • 步骤 1: 反转中缀表达式。 请注意,反转时每个“(”将变为“)”,每个“)”将变为“(”。
  • 步骤2: 将反转的中 缀表达式转换为“nearly”后缀表达式
    • 在转换为后缀表达式时,我们不会使用弹出操作来弹出优先级大于或等于的运算符,这里我们只将优先级更高的运算符从堆栈中弹出。
  • 步骤3: 反转后缀表达式。

堆栈用于将中缀表达式转换为后缀形式。

插图:

请参阅下图以获得清晰的想法:

将中缀表达式转换为前缀表达式

将中缀表达式转换为前缀表达式

下面是该算法的 C++ 实现。

C++

// C++ program to convert infix to prefix
#include <bits/stdc++.h>
using namespace std;
 
// Function to check if the character is an operator
bool isOperator(char c)
{
    return (!isalpha(c) && !isdigit(c));
}
 
// Function to get the priority of operators
int getPriority(char C)
{
    if (C == '-' || C == '+')
        return 1;
    else if (C == '*' || C == '/')
        return 2;
    else if (C == '^')
        return 3;
    return 0;
}
 
// Function to convert the infix expression to postfix
string infixToPostfix(string infix)
{
    infix = '(' + infix + ')';
    int l = infix.size();
    stack<char> char_stack;
    string output;
 
    for (int i = 0; i < l; i++) {
 
        // If the scanned character is an
        // operand, add it to output.
        if (isalpha(infix[i]) || isdigit(infix[i]))
            output += infix[i];
 
        // If the scanned character is an
        // ‘(‘, push it to the stack.
        else if (infix[i] == '(')
            char_stack.push('(');
 
        // If the scanned character is an
        // ‘)’, pop and output from the stack
        // until an ‘(‘ is encountered.
        else if (infix[i] == ')') {
            while (char_stack.top() != '(') {
                output += char_stack.top();
                char_stack.pop();
            }
 
            // Remove '(' from the stack
            char_stack.pop();
        }
 
        // Operator found
        else {
            if (isOperator(char_stack.top())) {
                if (infix[i] == '^') {
                    while (
                        getPriority(infix[i])
                        <= getPriority(char_stack.top())) {
                        output += char_stack.top();
                        char_stack.pop();
                    }
                }
                else {
                    while (
                        getPriority(infix[i])
                        < getPriority(char_stack.top())) {
                        output += char_stack.top();
                        char_stack.pop();
                    }
                }
 
                // Push current Operator on stack
                char_stack.push(infix[i]);
            }
        }
    }
    while (!char_stack.empty()) {
        output += char_stack.top();
        char_stack.pop();
    }
    return output;
}
 
// Function to convert infix to prefix notation
string infixToPrefix(string infix)
{
    // Reverse String and replace ( with ) and vice versa
    // Get Postfix
    // Reverse Postfix
    int l = infix.size();
 
    // Reverse infix
    reverse(infix.begin(), infix.end());
 
    // Replace ( with ) and vice versa
    for (int i = 0; i < l; i++) {
 
        if (infix[i] == '(') {
            infix[i] = ')';
        }
        else if (infix[i] == ')') {
            infix[i] = '(';
        }
    }
 
    string prefix = infixToPostfix(infix);
 
    // Reverse postfix
    reverse(prefix.begin(), prefix.end());
 
    return prefix;
}
 
// Driver code
int main()
{
    string s = ("x+y*z/w+u");
   
    // Function call
    cout << infixToPrefix(s) << std::endl;
    return 0;
}


          

Java

Python3

C#

Javascript

输出

++x/*yzwu

复杂度分析:

  • 时间复杂度:  O(n)
    • 像push()和pop()这样的堆栈操作是在恒定时间内执行的。 
    • 因为一旦复杂度随时间呈线性关系,我们就会扫描表达式中的所有字符
  • 辅助空间 :O(n),因为我们要保留一个堆栈。

Que votre objectif soit la réussite d'un examen, le développement professionnel ou un intérêt purement personnel, ce site de visualisation des structures de données et des algorithmes sera une ressource inestimable.

Rendez-vous sur ce site et commencez votre voyage d'apprentissage !

Voici les plus courants : 【Description en langage C】Structures de données et algorithmes Implémentation JAVA des structures de données Fondamentaux des structures de données et algorithmes (Université de Qingdao - Wang Zhuo) Structures de données et algorithmes Structures de données selon Wang Dao Implémentation en langage C des structures de données Cours intensif de structures de données pour les examens de fin de semestre Tutoriel vidéo sur les structures de données en langage C Yan Weimin sur les structures de données Hao Bin sur les structures de données Examen d'entrée en master sur les structures de données Algorithmes et fondamentaux des structures de données en JAVA Structures de données selon Wang Dao 2022 Apprentissage des structures de données Structures de données selon Xiao Jiayu Wang Zhuo Apprentissage des structures de données Structures de données à l'Université du Zhejiang Révision des structures de données Structures de données selon Ma Shibin Cours zéro sur les structures de données Structures de données et algorithmes Introduction aux structures de données Explication des exercices de structures de données pour l'examen d'entrée en master Révision de fin de semestre des structures de données Niveau 2 en informatique