This question already has answers here:
Handling parenthesis while converting infix expressions to postfix expressions
(2 answers)
Closed 5 years ago.
I've been working on a school assignment that requires us to convert a string from infix notation to postfix notation. We have to do this by using a stack implementing an array.
Here is my code for the actual conversion class:
package practice;
public class Practice {
public static String infixToPostfix(String infix)
{
Practice2 operatorStack = new Practice2();
String output = "";
char curChar;
String input = infix;
boolean isOperator=false;
boolean empty=true;
int curCharPrecedence=0;
int topOfStackPrecedence=0;
for(int i =0; i<input.length();i++){
curChar = input.charAt(i);
switch(curChar){
case '+': isOperator=true;
case '-': isOperator=true;
case '/': isOperator=true;
case '*': isOperator=true;
case '(': isOperator=true;
case ')': isOperator=true;
break;
default: isOperator=false;
}
if(!isOperator){
output=output+curChar;
}
else if(isOperator){
output+=" ";
if(empty){
empty=false;
operatorStack.Push(curChar);
}
else if(!operatorStack.empty()){
switch(curChar){
case ')': topOfStackPrecedence=0;
case '+': curCharPrecedence=1;
case '-': curCharPrecedence=1;
case '/': curCharPrecedence=2;
case '*': curCharPrecedence=2;
case '(': topOfStackPrecedence=3;
}
switch((Character) operatorStack.peek()){
case ')': topOfStackPrecedence=0;
case '+': topOfStackPrecedence=1;
case '-': topOfStackPrecedence=1;
case '/': topOfStackPrecedence=2;
case '*': topOfStackPrecedence=2;
case '(': topOfStackPrecedence=3;
}
if(curCharPrecedence>topOfStackPrecedence){
operatorStack.Push(curChar);
}
else{
while(!operatorStack.empty()&&topOfStackPrecedence>curCharPrecedence){
output+= operatorStack.pop();
output+=" ";
if(!operatorStack.empty())
switch((Character) operatorStack.peek()){
case ')': topOfStackPrecedence=0;
case '+': topOfStackPrecedence=1;
case '-': topOfStackPrecedence=1;
case '/': topOfStackPrecedence=2;
case '*': topOfStackPrecedence=2;
case '(': topOfStackPrecedence=3;
}
}
operatorStack.Push(curChar);
}
}
}
}
while(!operatorStack.empty()){
output+=" ";
output+= operatorStack.pop();
}
return output;
}
public static void main(String[] args)
{
System.out.println(infixToPostfix("a+b*c"));
}
}
Then here is my code for the stack class:
package practice;
import java.util.EmptyStackException;
public class Practice2<T> extends Object{
public T[] stack = (T[]) new Object[10];
int topOfStack =-1;
public Practice2()
{
stack = (T[]) new Object[10];
}
public Practice2(int capacity)
{
stack = (T[]) new Object[capacity];
}
public T Push(Object item)
{
if(topOfStack<=stack.length-1){
T[] temporary = (T[]) new Object[stack.length];
for(int i=0; i<stack.length-1;i++){
temporary[i]=stack[i];
}
stack = (T[]) new Object[temporary.length+10];
for(int i=0; i<temporary.length-1;i++){
stack[i]=temporary[i];
}
}
topOfStack++;
stack[topOfStack]= (T) item;
return (T) item;
}
public T peek()
{
return stack[topOfStack];
}
public T pop()
{
if(topOfStack==-1){
throw new EmptyStackException();
}
else
return stack[topOfStack--];
}
public boolean empty()
{
if(topOfStack==-1)
return true;
else
return false;
}
public int size(){
return topOfStack+1;
}
}
Whenever I try to run this I get the following error message:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at practice.Practice2.peek(Practice2.java:49)
at practice.Practice.infixToPostfix(Practice.java:53)
at practice.Practice.main(Practice.java:106
It appears that the problem is my peek method in the stack class, but I'm not entirely sure.
Any help is greatly appreciated, I've spent way to much time on this program and badly need someone else to take a look at it.
The error is quite clear ArrayIndexOutOfBoundsException ....
and the reason is here:
switch((Character) operatorStack.peek()){
you are doing a peek before a push... more specific: you are trying to get the element of the array located at the topOfStack =-1 and that is the reason of the exception...
Related
public class JsonValidator {
public static boolean isValidJSON(String jsonString) {
Stack<Character> stack = new Stack<>();
for (char c : jsonString.toCharArray()) {
switch (c) {
case '{':
stack.push(c);
break;
case '}':
if (stack.isEmpty()) {
return false;
}
Character last1 = stack.pop();
if (last1 != '{') {
return false;
}
break;
case '[':
stack.push(c);
break;
case ']':
if (stack.isEmpty()) {
return false;
}
Character last2 = stack.pop();
if (last2 != '[') {
return false;
}
break;
case '\"':
if (stack.isEmpty()) {
return false;
}
Character last3 = stack.peek();
if (last3 == '\"') {
stack.pop();
} else {
stack.push(c);
}
stack.push(c);
}
}
return stack.isEmpty();
}
assertTrue(JsonValidator.isValidJSON(""{""), "The brackets and quotes are balanced, making this a valid JSON string");
This is one of my test cases, its supposed to be valid JSON but it keeps giving me false
The problem with your checker is that when you check "{" you are pushing characters onto the stack that are never going to be popped. Hence, the stack is not empty.
Hint: look carefully at what is being pushed and popped when you process a string.
Also, your parser is not dealing with escapes in strings at all. And a { or } or [ or ] encountered within a JSON string should be treated as regular data.
So this little function is supposed to check if parentheses and brackets are matched next to each other. I feel like it should work and I've tried it a few different ways but I can't figure out how to check if my next char is what I expect it to be.
class Parenths {
public boolean isValid(String s) {
char[] parens = s.toCharArray();
if (parens.length == 0) return true;
for (int i = 0; i < parens.length; i+=2) {
String curr= String.valueOf(parens[i]);
String next = String.valueOf(parens[i+1]);
// System.out.println(next.equals(")"); --------> false
// System.out.println(Object.equals(next, ")")); ----> error
switch (curr) {
case "(": if (!next.equals(")")) return false;
case "{": if (!next.equals("}")) return false;
case "[": if (!next.equals("]")) return false;
}
}
return true;
}
}
You can see the lines I printed to debug and it seems that .equals is not the right thing to use here? Can anyone explain why this isn't working?
PS. I realize I don't have to convert the string to a char array to compare elements, so unless that's the only fix, please don't point that out to me.
Not tested, but it seems to be a problem of fall through. Try to replace if (boolean) return boolean with return boolean, this should do the trick.
The problem is that you don't have a break at the end of the cases, so if, for example, your first case is true, it will not stop execution and execute the 2nd test, which will be false. If you change your conditional statements to a direct return, you will not have this problem.
EDIT: Sorry, I read too quickly. Doing so will break your loop. Actually, you have to add a break at the end of the cases.
case "(": if (!next.equals(")")) return false; break;
case "{": if (!next.equals("}")) return false; break;
case "[": if (!next.equals("]")) return false; break;
First , you have to add break; after the cases its important to stop seeing the cases
switch (curr) {
case "(": if (!next.equals(")")) return false;
break;
case "{": if (!next.equals("}")) return false;
break;
case "[": if (!next.equals("]")) return false;
break;
}
Secondly , your code doesnt support the confrotation of a closing patenthesis at first , you have to add a default case
switch (curr) {
case "(": if (!next.equals(")")) return false;
break;
case "{": if (!next.equals("}")) return false;
break;
case "[": if (!next.equals("]")) return false;
break;
default :
break;
}
return true;
Also , you have to make sure the next element is not null before comparing to it , and dont increment with 2 , you give a String with a one element and that's why you get the error
public static boolean isValid(String s) {
char[] parens = s.toCharArray();
if (parens.length == 0) return true;
for (int i = 0; i < parens.length; i++) {
String curr= String.valueOf(parens[i]);
String next = "";
try {
next = String.valueOf(parens[i+1]);
switch (curr) {
case "(": if (!next.equals(")")) return false;
break;
case "{": if (!next.equals("}")) return false;
break;
case "[": if (!next.equals("]")) return false;
break;
default :
break;
}
return true;
}catch(Exception e) {}
}
return false;
}
Test :
System.out.println(isValid("()"));
// Output : true
System.out.println(isValid("("));
// Output : false
So I was assigned to create an method which takes in a string in infix notation as a parameter and returns a string in postfix notation.
My code seems to work for most examples I throw at it, but a few inputs cause wacky results.
public class Operations<T> {
public int value(char c){
switch(c){
case '(':
case ')':
return 3;
case '*':
case '/':
case '%':
return 2;
case '+':
case '-':
return 1;
default:
return 0;
}
}
public String infixToPostfix(String infix){
//Operator stack
myStack<Character> ops = new myStack<Character>();
//Postfix string
String postfix = "";
//Current char being read
char c;
//Marks if paranthesis are being passed in
boolean flag = false;
//Iterate through each character to find operators
for(int i=0; i<infix.length(); i++){
c = infix.charAt(i);
//Add operand to postfix and operator to stack
if(value(c)==0){
postfix+=c;
} else if(ops.isEmpty() || (value(c)>value(ops.getTop()) && c!=')') || c=='(') {
ops.push(c);
} else if(value(c)<value(ops.getTop()) && c!=')') {
if(ops.getTop()=='(' || flag) {
ops.push(c);
flag = true;
} else {
postfix+=ops.pop();
while(!ops.isEmpty() && value(c)<value(ops.getTop())) {
postfix+=ops.pop();
}
ops.push(c);
}
} else if(c==')') {
while(ops.getTop()!='('){
postfix+=ops.pop();
}
ops.pop();
flag = false;
} else {
postfix+=ops.pop();
ops.push(c);
}
}
while(!ops.isEmpty()){
postfix+=ops.pop();
}
return postfix;
}
}
for example, the equation:
- A * B + (C/D*7) – ( (A%C-8) / (H+F-D))
outputs:
ABCD/7+AC8-%HF+D-/-
while the correct answer is:
ABCD/7+AC%8-HF+D-/
What is causing the problem? Thanks
Here's a method I wrote to check which operator has the highest precedence, now my question is: is there any other way I can do this? I have been testing this one and it works fine, but I'm pretty sure there should be room for improvement. What do you think?
static boolean hasHigherPrecendence(char top, char current){
String t = String.valueOf(top);
String c = String.valueOf(current);
System.out.println(t);
System.out.println(c);
switch (t) {
case "-":
if ( c.equals("-") || c.equals("+") )
return false;
break;
case "+":
if ( c.equals("-") || c.equals("+") )
return false;
break;
case "/":
if ( !c.equals("*") || !c.equals(t) || !c.equals("%") )
return false;
break;
case "*":
if ( !c.equals("%") || !c.equals(t) || !c.equals("/"))
return false;
break;
case "%":
if (c.equals(t) || c.equals("*") || c.equals("/"))
return false;
break;
default:
throw new IllegalArgumentException("Operator unknown: " + t);
}
return true;
}
If it were me I would rank the operators in a function (note, the values I chose are not necessarily the ones you should use ...):
private static final int rankOperator(char op) {
switch (op) {
case '-' : return 0;
case '+' : return 0;
case '/' : return 2;
case '*' : return 2;
case '%' : return 4;
}
throw new IllegalStateException("Unknown operator " + op);
}
public boolean hasHigherPrecedence(char top, char current) {
return rankOperator(top) > rankOperator(current);
}
Apart of using maps, arrays, functions... you can reduce your code using the concatenating the cases with the same behaviour:
static boolean hasHigherPrecendence(char top, char current){
String t = String.valueOf(top);
String c = String.valueOf(current);
System.out.println(t);
System.out.println(c);
switch (t) {
case "-":
case "+":
if ( c.equals("-") || c.equals("+") )
return false;
break;
case "/":
case "*":
case "%":
if (c.equals("%") || c.equals("*") || c.equals("/"))
return false;
break;
default:
throw new IllegalArgumentException("Operator unknown: " + t);
}
return true;
}
static boolean hasHigherPrecendence(char top, char current){
Map<Character,Integer> map = new HashMap<>();
map.put('+',new Integer(1));
map.put('-',new Integer(1));
map.put('*',new Integer(2));
map.put('/',new Integer(2));
map.put('%',new Integer(3));
if( map.get(top)==null ){
throw new IllegalArgumentException("Operator unknown: " + top);
}
if( map.get(current)==null ){
throw new IllegalArgumentException("Operator unknown: " + current);
}
if(map.get(t) >= map.get(c)){
return true;
}else{
return false;
}
}
Can you explain how can I Add?
My Infix is: 1^2+3/3
Prefix expression is: +1^2/33 (which is wrong)
Postfix expression is: 1^233/+ (which is wrong)
the Prefix will be: +^12/33
and the Postfix will be: 12^33/+
My Code:
import java.io.*;
class Stack
{
private char[] a;
private int top,m;
public Stack(int max)
{
m=max;
a=new char[m];
top=-1;
}
public void push(char key)
{
a[++top]=key;
}
public char pop()
{
return(a[top--]);
}
public char peek()
{
return(a[top]);
}
public boolean isEmpty()
{
return (top==-1);
}
}
class Evaluation
{
private Stack s;
private String input;
private String output="";
public Evaluation(String str)
{
input=str;
s=new Stack(str.length());
}
public String inToPre()
{
for(int i=input.length()-1;i>=0;i--)
{
char ch=input.charAt(i);
**switch(ch)
{
case '+':
case '-':gotOperator(ch,1,')');
break;
case '*':
case '/':gotOperator(ch,2,')');
break;
case ')':s.push(ch);
break;
case '(':gotParenthesis(')');
break;
default:output=ch+output;
}
}
while(!s.isEmpty())
output=s.pop()+output;
return output;
} // End to inToPre
public String inToPost()
{
for(int i=0;i<input.length();i++)
{
char ch=input.charAt(i);
switch(ch)
{
case '+':
case '-':gotOperator(ch,1,'(');
break;
case '*':
case '/':gotOperator(ch,2,'(');
break;
case '(':s.push(ch);
break;
case ')':gotParenthesis('(');
break;
default:output=output+ch;
}
}
while(!s.isEmpty())
output=output+s.pop();
return output;
} // End inToPost**
private void gotOperator(char opThis,int prec1,char x)
{
while(!s.isEmpty())
{
char opTop=s.pop();
if(opTop==x)
{
s.push(opTop);
break;
}
else
{
int prec2;
if(opTop=='+'||opTop=='-')
prec2=1;
else
prec2=2;
if(prec2<prec1&&x=='(')
{
s.push(opTop);
break;
}
else if(prec2<=prec1&&x==')')
{
s.push(opTop);
break;
}
else
{
if(x==')')
output=opTop+output;
else
output=output+opTop;
}
}
} // End While gotOperator
s.push(opThis);
} // End gotOperator
private void gotParenthesis(char x)
{
while(!s.isEmpty())
{
char ch=s.pop();
if(ch==x)
break;
else
{
if(x==')')
output=ch+output;
else
output=output+ch;
} // End Else
} // End While gotParenthesis
} // End gotParenthesis
} // End Class Evaluation
Just looking at your code quickly I can see that in the InFix analysis you are not considering a new level for the ^ operator.
The groups should be +-, */, ^. Since the ^ has higher priority.
Regards