正在载入交互式动画窗口请稍等
栈-表达式计算-顺序表 可视化交互式动画版
编写一个程序将 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+ 。 可以使用堆栈轻松计算后缀表达式。
如何将中缀表达式转换为后缀表达式?
要将中缀表达式转换为后缀表达式,请使用 堆栈数据结构 。 从左到右扫描中缀表达式。 每当我们得到一个操作数时,将其添加到后缀表达式中,如果我们得到一个运算符或括号,则通过保持其优先级将其添加到堆栈中。
下面是实现上述想法的步骤:
- 从左到右 扫描中缀表达式 。
- 如果扫描到的字符是操作数,则将其放入后缀表达式中。
-
否则,请执行以下操作
-
如果扫描到的运算符的优先级和结合性大于栈中运算符的优先级和结合性[或者栈为空或栈中包含'('],则将其压入栈中。['
^
'
运算
符是右关联的,而其他运算符如“
+
”、“
-
”、“
*
”和“
/
”是左关联]。
- 特别检查堆栈顶部的运算符和扫描的运算符均为“ ^ ”时的情况。 在这种情况下,由于其右结合性,扫描运算符的优先级较高。 所以它会被压入操作符栈。
- 在所有其他情况下,当运算符堆栈的顶部与扫描的运算符相同时,则从堆栈中弹出该运算符,因为左关联性导致扫描的运算符具有较低的优先级。
-
否则,从堆栈中弹出所有优先级大于或等于扫描到的运算符的运算符。
- 完成此操作后,将扫描的运算符推入堆栈。 (如果在弹出时遇到括号,则停在那里并将扫描的运算符推入堆栈。)
-
如果扫描到的运算符的优先级和结合性大于栈中运算符的优先级和结合性[或者栈为空或栈中包含'('],则将其压入栈中。['
^
'
运算
符是右关联的,而其他运算符如“
+
”、“
-
”、“
*
”和“
/
”是左关联]。
- 如果扫描到的字符是' ( ',则将其压入堆栈。
- 如果扫描到的字符是' ) ',则出栈并输出,直到遇到' ( ',并丢弃两个括号。
- 重复步骤 2-5 ,直到扫描到中缀表达式。
- 扫描结束后,弹出堆栈并添加后缀表达式中的运算符,直到不为空。
- 最后,打印后缀表达式。
插图:
请按照下图更好地理解
考虑中缀表达式 exp = “a+b*c+d”并使用迭代器 i
扫描中缀表达式 ,迭代器初始化为 i = 0 。第一步: 这里 i = 0 且 exp[i] = 'a' 即操作数。 所以将其添加到后缀表达式中。 因此, postfix =“a” 。
第二步: 这里 i = 1 且 exp[i] = '+' 即运算符。 将其推入堆栈。 postfix = “a” 和 stack = {+} 。
第三步: 现在 i = 2 且 exp[i] = 'b' 即操作数。 所以将其添加到后缀表达式中。 后缀 = “ab” 和 堆栈 = {+} 。
第四步: 现在 i = 3 且 exp[i] = '*' 即一个运算符。 将其推入堆栈。 postfix = “ab” 和 stack = {+, *} 。
第五步: 现在 i = 4 且 exp[i] = 'c' 即操作数。 将其添加到后缀表达式中。 postfix = “abc” 和 stack = {+, *} 。
第六步: 现在 i = 5 且 exp[i] = '+' 即一个运算符。 堆栈最顶层的元素具有更高的优先级。 因此弹出直到堆栈变空或顶部元素的优先级较低。 '*' 被弹出并添加到后缀中。 所以 postfix = “abc*” 和 stack = {+} 。
现在顶部元素是“ + ”,它的优先级也没有降低。 弹出它。 后缀=“abc*+” 。
现在堆栈是空的。 因此将 “+” 压入堆栈。 堆栈= {+} 。
第七步: 现在 i = 6 且 exp[i] = 'd' 即操作数。 将其添加到后缀表达式中。 后缀=“abc*+d” 。
最后一步: 现在没有留下任何元素。 因此清空堆栈并将其添加到后缀表达式中。 后缀=“abc*+d+” 。
下面是上述算法的实现:
- C++14
- C
- Java
- Python3
- C#
- JavaScript
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++
- Java
- Python3
- C#
- JavaScript
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),因为我们要保留一个堆栈。