使用 Stacks Java 中缀到 Postfix
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26699089/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Infix to Postfix using Stacks Java
提问by OneMoreError
I am trying to write a program to convert an infix expression to a postfix expression.
我正在尝试编写一个程序来将中缀表达式转换为后缀表达式。
The algorithm that I am using is as follows :
我使用的算法如下:
1. Create a stack
2. For each character t in the expression
- If t is an operand, append it to the output
- Else if t is ')',then pop from the stack till '(' is encountered and append
it to the output. do not append '(' to the output.
- If t is an operator or '('
-- If t has higher precedence than the top of the stack, then push t
on to the stack.
-- If t has lower precedence than top of the stack, then keep popping
from the stack and appending to the output until either stack is
empty or a lower priority operator is encountered.
After the input is over, keep popping and appending to the output until the
stack is empty.
Here is my code which prints out wrong results.
这是我打印出错误结果的代码。
public class InfixToPostfix
{
private static boolean isOperator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^'
|| c == '(' || c == ')';
}
private static boolean isLowerPrecedence(char op1, char op2)
{
switch (op1)
{
case '+':
case '-':
return !(op2 == '+' || op2 == '-');
case '*':
case '/':
return op2 == '^' || op2 == '(';
case '^':
return op2 == '(';
case '(':
return true;
default:
return false;
}
}
public static String convertToPostfix(String infix)
{
Stack<Character> stack = new Stack<Character>();
StringBuffer postfix = new StringBuffer(infix.length());
char c;
for (int i = 0; i < infix.length(); i++)
{
c = infix.charAt(i);
if (!isOperator(c))
{
postfix.append(c);
}
else
{
if (c == ')')
{
while (!stack.isEmpty() && stack.peek() != '(')
{
postfix.append(stack.pop());
}
if (!stack.isEmpty())
{
stack.pop();
}
}
else
{
if (!stack.isEmpty() && !isLowerPrecedence(c, stack.peek()))
{
stack.push(c);
}
else
{
while (!stack.isEmpty() && isLowerPrecedence(c, stack.peek()))
{
Character pop = stack.pop();
if (pop != '(')
{
postfix.append(pop);
}
}
}
stack.push(c);
}
}
}
return postfix.toString();
}
public static void main(String[] args)
{
System.out.println(convertToPostfix("A*B-(C+D)+E"));
}
}
The program should print AB*CD+-E+
but it is printing AB*-CD+E
.
Why is the output incorrect ?
该程序应该打印,AB*CD+-E+
但它正在打印AB*-CD+E
。为什么输出不正确?
Also, Is there a more elegant solution to this problem. Please share if you have or know one.
另外,是否有更优雅的解决方案来解决这个问题。有或者知道的请分享一下。
采纳答案by SMA
Issue is with your else part:
问题在于您的其他部分:
if (!stack.isEmpty() && !isLowerPrecedence(c, stack.peek()))
{
stack.push(c);
}
else
{
while (!stack.isEmpty() && isLowerPrecedence(c, stack.peek()))
{
Character pop = stack.pop();
if (pop != '(')
{
postfix.append(pop);
}
}
}
stack.push(c);
So here you are pushing the same c element twice with stack.push() when you see stack is not empty and precedence match is higher.
因此,当您看到堆栈不为空且优先级匹配更高时,您将使用 stack.push() 两次推送相同的 c 元素。
So put this stack.push within else part or remove the push from if condition.
所以把这个 stack.push 放在 else 部分或者从 if 条件中删除推送。
Another issue is, when at the end you have some operators within the stack you dont pop them out.
另一个问题是,当最后您在堆栈中有一些运算符时,您不会将它们弹出。
Here's the code that i came up with for your case:
这是我为您的案例提出的代码:
private static boolean isOperator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^'
|| c == '(' || c == ')';
}
private static boolean isLowerPrecedence(char op1, char op2)
{
switch (op1)
{
case '+':
case '-':
return !(op2 == '+' || op2 == '-');
case '*':
case '/':
return op2 == '^' || op2 == '(';
case '^':
return op2 == '(';
case '(':
return true;
default:
return false;
}
}
public static String convertToPostfix(String infix)
{
Stack<Character> stack = new Stack<Character>();
StringBuffer postfix = new StringBuffer(infix.length());
char c;
for (int i = 0; i < infix.length(); i++)
{
c = infix.charAt(i);
if (!isOperator(c))
{
postfix.append(c);
}
else
{
if (c == ')')
{
while (!stack.isEmpty() && stack.peek() != '(')
{
postfix.append(stack.pop());
}
if (!stack.isEmpty())
{
stack.pop();
}
}
else
{
if (!stack.isEmpty() && !isLowerPrecedence(c, stack.peek()))
{
stack.push(c);
}
else
{
while (!stack.isEmpty() && isLowerPrecedence(c, stack.peek()))
{
Character pop = stack.pop();
if (c != '(')
{
postfix.append(pop);
} else {
c = pop;
}
}
stack.push(c);
}
}
}
}
while (!stack.isEmpty()) {
postfix.append(stack.pop());
}
return postfix.toString();
}
public static void main(String[] args)
{
System.out.println(convertToPostfix("A*B-(C+D)+E"));
}
回答by sam_k
I think above answer is not correct.
我认为上面的答案是不正确的。
This is the version corrected by me :
这是我更正的版本:
package Stack;
import java.util.Stack;
/*
*
Algorithm
1. Scan the infix expression from left to right.
2. If the scanned character is an operand, output it.
3. Else,
…..3.1 If the precedence of the scanned operator is greater than the precedence of the operator in the stack(or the stack is empty), push it.
…..3.2 Else, Pop the operator from the stack until the precedence of the scanned operator is less-equal to the precedence of the operator residing on the top of the stack. Push the scanned operator to the stack.
4. If the scanned character is an ‘(‘, push it to the stack.
5. If the scanned character is an ‘)', pop and output from the stack until an ‘(‘ is encountered.
6. Repeat steps 2-6 until infix expression is scanned.
7. Pop and output from the stack until it is not empty.
*/
public class InfixToPostFixEvalution {
private static boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '(' || c == ')';
}
private static int getPrecedence(char ch) {
switch (ch) {
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
return 3;
}
return -1;
}
// A utility function to check if the given character is operand
private static boolean isOperand(char ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}
public static String convertToPostfix(String infix) {
Stack<Character> stack = new Stack<Character>();
StringBuffer postfix = new StringBuffer(infix.length());
char c;
for (int i = 0; i < infix.length(); i++) {
c = infix.charAt(i);
if (isOperand(c)) {
postfix.append(c);
} else if (c == '(') {
stack.push(c);
}
// If the scanned character is an ‘)', pop and output from the stack
// until an ‘(‘ is encountered.
else if (c == ')') {
while (!stack.isEmpty() && stack.peek() != '(') {
postfix.append(stack.pop());
}
if (!stack.isEmpty() && stack.peek() != '(')
return null;
else if(!stack.isEmpty())
stack.pop();
}
else if (isOperator(c)) // operator encountered
{
if (!stack.isEmpty() && getPrecedence(c) <= getPrecedence(stack.peek())) {
postfix.append(stack.pop());
}
stack.push(c);
}
}
while (!stack.isEmpty()) {
postfix.append(stack.pop());
}
return postfix.toString();
}
public static void main(String[] args) {
System.out.println(convertToPostfix("a+b*(c^d-e)^(f+g*h)-i"));
}
}
回答by Krishna
This code inserts the "(" as well in stack and removes accordingly. Just another way of implementing infix to postfix. Here the check is until I do not find lower priority operator in stack I will pop out the value. e.g if stack has - and next operator is +, it will pop - as it is of equal priority.
这段代码在堆栈中插入“(”并相应地删除。这是实现中缀到后缀的另一种方式。这里的检查是,直到我在堆栈中找不到低优先级的运算符,我才会弹出该值。例如,如果堆栈有 -下一个运算符是 +,它会弹出 - 因为它具有相同的优先级。
I have added custom stack implementation, however normal stack provide by java can also be used in place
我添加了自定义堆栈实现,但是也可以使用 java 提供的普通堆栈
import chapter4.LinkedListStack(custom stack implementation);
public class InfixToPostfix {
public String infixToPostfix(String str) {
LinkedListStack<String> stack = new LinkedListStack<>();
String[] st = str.split("");
String result = "";
for (String s : st) {
if (operator(s)) {
if (")".equals(s)) {
while (!stack.isEmpty() && !"(".equals(stack.getTop())) {
result += stack.pop();
}
if (!stack.isEmpty()) {
stack.pop();
}
} else {
if (!stack.isEmpty() && !isLowerPrecedence(s, stack.getTop())) {
stack.push(s);
} else {
while (!stack.isEmpty() && isLowerPrecedence(s, stack.getTop())) {
String top = stack.pop();
if (!"(".equals(top)) {
result += top;
}
}
stack.push(s);
}
}
} else {
result += s;
}
}
while (!stack.isEmpty()) {
result += stack.pop();
}
return result;
}
private boolean isLowerPrecedence(String s, String s1) {
switch (s) {
case "+":
return !("+".equals(s1) || "(".equals(s1));
case "-":
return !("-".equals(s1) || "(".equals(s1));
case "*":
return "/".equals(s1) || "^".equals(s1) || "(".equals(s1);
case "/":
return "*".equals(s1) || "^".equals(s1) || "(".equals(s1);
case "^":
return "(".equals(s1);
case "(":
return false;
default:
return false;
}
}
private boolean operator(String s) {
return "+".equals(s) || "-".equals(s) || "*".equals(s) || "/".equals(s) || "^".equals(s) || "(".equals(s) ||
")".equals(s);
}
public static void main(String[] args) {
InfixToPostfix itp = new InfixToPostfix();
System.out.println("The Postfix expression for A*B-(C+D)+E is: " + itp.infixToPostfix("A*B-(C+D)+E"));
System.out.println("The Postfix expression for 1+2*4/5-7+3/6 is: " + itp.infixToPostfix("1+2*4/5-7+3/6"));
System.out.println("The Postfix expression for a+(b*c)/d is: " + itp.infixToPostfix("a+(b*c)/d"));
}
}
public class LinkedListStack<E> {
private Node<E> head;
private static class Node<E> {
E item;
Node<E> next;
public Node(E item, Node<E> next) {
this.item = item;
this.next = next;
}
}
public void push(E item) {
System.out.println("push: " + item);
Node<E> newNode = new Node<>(item, null);
newNode.next = head;
head = newNode;
}
public E pop() {
if (isEmpty()) {
System.out.println("stack is Empty -> empty stack exception");
return null;
}
System.out.println("pop: " + head.item);
E data = head.item;
head = head.next;
return data;
}
public boolean isEmpty() {
return head == null;
}
public E getTop() {
return head.item;
}
}
回答by N.CY
I think the problem is here:
我认为问题出在这里:
private static boolean isLowerPrecedence(char op1, char op2)
{
switch (op1)
{
.....
case '(':
return true;
.....
}
In the case '(', false should be returned.
在'('的情况下,应该返回false。
回答by OlaB
This solution requires proper braces around the original expression, but its quite simple and straight forward compared to other answers I looked at. Just for someone who might need it because the post is an old post.
该解决方案需要在原始表达式周围使用适当的括号,但与我查看的其他答案相比,它非常简单明了。仅适用于可能需要它的人,因为该帖子是旧帖子。
public static String InfixToPostfix(String origin)
{
String[] params = origin.split(" ");
Stack<String> ops = new Stack<>();
Stack<String> vals = new Stack<>();
for (int i = 0; i < params.length; i++)
{
switch (params[i]) {
case "(":
;
break;
case "+":
ops.push(params[i]);
break;
case "-":
ops.push(params[i]);
break;
case "*":
ops.push(params[i]);
break;
case "/":
ops.push(params[i]);
break;
case "sqrt":
ops.push(params[i]);
break;
// Token not operator or paren: push double value.
case ")":
String d1 = vals.pop();
String d2 = vals.pop();
String op = ops.pop();
vals.push("( " + d2 + " " + d1 + " "+ op + " )");
break;
default:
vals.push(params[i]);
break;
}
}
// System.out.print(vals.pop());
return vals.pop();
}