Infix to postfix not working as expected [duplicate] - java

This question already has answers here:
Handling parenthesis while converting infix expressions to postfix expressions
(2 answers)
Closed 5 years ago.
I have this homework in Java where I have to convert an infix string without parenthesis to a postfix string. I've been tinkering with the code from two days but I haven't been able to catch the bug. Here's my code.
public class itp
{
String exp, post;
double res;
int l;
stack st;
public itp(String s)
{
exp = s;
post = "";
l = exp.length();
st = new stack(l);
conv();
calc();
System.out.println("The postfix notation of "+exp+" is "+post);
System.out.println("The result of "+exp+" is "+res);
}
public void conv()
{
char ch = ' ';
char pre = ' ';
for(int i =0;i<l;i++)
{
ch = exp.charAt(i);
if("+-*/".indexOf(ch)==-1)post = post + ch;
else
{
pre = st.pop();
if(val(ch)>=val(pre))
{
st.push(pre);
st.push(ch);
}
else
{
while((val(ch)<=val(pre))&&(pre!='$'))
{
post = post + pre;
pre = st.pop();
}
st.push(ch);
}
}
}
for(pre = st.pop();pre!='$';pre = st.pop())
{
post = post + pre;
}
}
public void calc()
{
res = 0.0;
}
public int val(char c)
{
switch(c)
{
case '$' : return 0;
case '+' : return 1;
case '-' : return 2;
case '*' : return 3;
case '/' : return 4;
default : return -1;
}
}
}
Here, the variables are as follows:
st is a character stack
ch is the current character
pre is the topmost char on the stack
exp is the input infix expression
post is the output postfix expression
The pop() methods works as expected except when the stack is empty, where it will return $. The function val() takes a char input and returns 4 for /, 3 for *. 2 for -. 1 for +. The integer l holds the length of exp.
It works well in most cases except when I give it a string like a*b-b*c+c*d-d*e where it outputs ab*bc*-cd*de*- which is the expected output without a + in the end.
Any advice would be much appreciated. This bug is making me crazy!
Here's the entire code:
public class itp
{
String exp, post;
double res;
int l;
stack st;
public itp(String s)
{
exp = s;
post = "";
l = exp.length();
st = new stack(l);
conv();
calc();
System.out.println("The postfix notation of "+exp+" is "+post);
System.out.println("The result of "+exp+" is "+res);
}
public void conv()
{
char ch = ' ';
char pre = ' ';
for(int i =0;i<l;i++)
{
ch = exp.charAt(i);
if("+-*/".indexOf(ch)==-1)post = post + ch;
else
{
pre = st.pop();
if(val(ch)>=val(pre))
{
st.push(pre);
st.push(ch);
}
else
{
while((val(ch)<=val(pre))&&(pre!='$'))
{
post = post + pre;
pre = st.pop();
}
st.push(ch);
}
}
}
for(pre = st.pop();pre!='$';pre = st.pop())
{
post = post + pre;
}
}
public void calc()
{
res = 0.0;
}
public int val(char c)
{
switch(c)
{
case '$' : return 0;
case '+' : return 1;
case '-' : return 2;
case '*' : return 3;
case '/' : return 4;
default : return -1;
}
}
}
here's the stack class:
public class stack
{
char[] a;
int top,size;
public stack(int s)
{
size = s;
a = new char[size];
top = -1;
}
public void push(char el)
{
a[++top] = el;
}
public char pop()
{
if(empty()) return '$';
else return a[top--];
}
public boolean empty()
{
return (top == -1);
}
}
Here's the main class
import java.util.Scanner;
class client
{
public static void main(String args[])
{
System.out.println("Enter the expression");
Scanner in = new Scanner(System.in);
itp i = new itp(in.next());
}
}

First of all the post fix of a*b-b*c+c*d-d*e is not ab*bc*-cd*de*-+ but ab*bc*-cd*+de*-.
Secondly the mistake is in your val() function. It should instead be :
case '$' : return 0;
case '+' : return 1;
case '-' : return 1;
case '*' : return 2;
case '/' : return 2;
default : return -1;
Change it and check. It will certainly work.

Related

I'm trying to change infix to postfix in java, what is the problem?

I want to convert infix to postfix with stack data structure.
In this code, I didn't consider the case of * and /.
example input: 10 - ( 3 + 4 ) - 1
correct output is: 10 3 4 + - 1 -
but my output is: 10 3 4 + 1 - -
And this is part of my code. I checked some part that I thought that is wrong.
operator is name of stack I made.
public String infix to (String infix) throws ArrayIndexOutOfBoundsException {
int result=0;
arr = infix.split(" ");
String element = "";
String postfix="";
for(int i=0; i<arr.length; i++) {
element = arr[i];
if(element.equals("+")||element.equals("-")) {
operator.push(element);
}
else if(element.equals("(")) {
operator.push(element);
}
else if(element.equals(")")) {
//**As I think, this part might wrong**
while((!operator.empty())||(!operator.peek().equals("("))){
postfix = postfix.concat(operator.pop());
postfix = postfix.concat(" ");
if(operator.peek().equals("(")) {
operator.pop();
}
break;
}
}
else if(isNum(element)){
postfix = postfix.concat(element);
postfix = postfix.concat(" ");
}
}
while(!operator.empty()) {
postfix = postfix.concat(operator.pop());
postfix = postfix.concat(" ");
}
return postfix;
}
public static boolean isNum(String s) {
try {
Integer.parseInt(s);
return true;
}
catch(NumberFormatException e) {
return false;
}
}
thank you all.
Change this (!operator.empty())||(!operator.peek().equals("(")) to (!operator.empty()) && (!operator.peek().equals("("))
while((!operator.empty()) && (!operator.peek().equals("("))){
postfix = postfix.concat(operator.pop());
postfix = postfix.concat(" ");
if( (!operator.empty()) && (!operator.peek().equals("("))) {
break; //invalid
else
operator.pop();
}
}

Why is my evalPostfix method not working?

In my Java program file, I am trying to write a method that will evaluate a postfix expression.
I am also trying to write an eval() method for my Expression class that evaluates an infix expression by first converting it to postfix and then evaluating the postfix.
For example, in main, if I write: eval("1 + 2 * 3") I should get 7.
However, in my program, when I write this, all it returns is -1.
Can anyone help me pinpoint the error in my code, either in the evalPostfix() or eval() methods?
public class Expression {
private static final String SPACE = " ";
private static final String PLUS = "+";
private static final String MINUS = "-";
public static int rank(String operator) {
switch (operator) {
case "^": //5
return 3;
case "*":
case "/":
return 2;
case PLUS:
case MINUS: //2
return 1;
case "()": //6
return 0;
default:
return -1;
}
}
public static boolean isOperator(String token) { //4
if (rank(token) > 0){
return true;
}
return false;
}
public static int applyOperator(String operator,int op1,int op2){ //7
switch (operator) {
case PLUS:
return op1+op2;
case MINUS:
return op1-op2;
case "*":
return op1*op2;
case "/":
return op1/op2;
case "^":
return (int) Math.pow( (double) op1, (double) op2); //9
default:
return -1;
}
}
public static String toPostfix(String infixExpr) {
StringBuilder output = new StringBuilder();
Stack<String> operators = new ArrayStack<>();
Stack<Character> s = new ArrayStack<Character>(); //6
for (int i = 0; i < infixExpr.length(); i++){
if(infixExpr.charAt(i) == '(');
s.push('(');
if(infixExpr.charAt(i) == ')' && !operators.isEmpty()){
s.pop();
if(s.isEmpty())
output.append(s.pop());
if(s.pop() != '(')
operators.pop();
}
}
for (String token: infixExpr.split("\\s+")) {
if (isOperator(token)) { // operator //4
// pop equal or higher precedence
while (!operators.isEmpty() &&
rank(operators.peek()) >= rank(token)) {
output.append(operators.pop() + SPACE);
}
operators.push(token);
} else { // operand
output.append(token + SPACE);
}
}
while (!operators.isEmpty()) {
output.append(operators.pop() + SPACE);
}
return output.toString();
}
public static int evalPostfix(String infixExpr) { //8
Stack <String> s = new ArrayStack<String>();
String operand = null;
for(int i = 0; i < infixExpr.length(); i++) {
if (Character.isDigit(infixExpr.charAt(i)))
s.push(infixExpr.charAt(i) + "");
else {
if (s.size() > 1) {
int value1 = Integer.parseInt(s.pop());
int value2 = Integer.parseInt(s.pop());
s.push(applyOperator(infixExpr.charAt(i) + "", value1, value2) + "");
}
}
}
return Integer.parseInt(s.pop());
}
public static int eval(String infix){
return evalPostfix(toPostfix(infix));
}
public static void main(String[] args) {
System.out.println(rank("/"));
String infix = "(a * b) * c + d ^ e / f";
String stat = "5 * 3";
System.out.println(toPostfix(infix));
System.out.print("Using applyOperator method, 7 * 3 = ");
System.out.println(applyOperator("*", 3, 7));
System.out.print("Using applyOperator method, 50 + 12 = ");
System.out.println(applyOperator("+", 50, 12));
System.out.print("Using Math.pow to perform exponentiation, 6 to the 2nd power is: ");
System.out.println(applyOperator("^", 6,2));
System.out.println(eval(stat));
}
}

Create an equation using Random and operators in Java

I'm trying to create a method that would create an equation for me, as a String.
For example, this method would create:
String formula = "5 + 3";
then another method will solve it.
I don't really know how to create the string. Should i use concat?
Thanks for all the help.
public static String getEquation() {
for(int i=0;i<7;i++){
int rand = rng.nextInt(5);
switch (rand) {
case 0:
operator = "+";
break;
case 1:
operator = "-";
break;
case 2:
operator = "*";
break;
case 3:
operator = "/";
break;
case 4:
operator = "(";
break;
case 5:
operator = ")";
}
}
return formula;
}
Wrote something up really quick, I think this should get you going. You'd have to handle the cases for parentheses though. I didn't account for that.
import java.util.Random;
public class Test {
static Random randomGenerator = new Random();
static String operators = "+-*/P"; //p = parentheses pair
public static char getRandomOperator() {
return operators.charAt(randomGenerator.nextInt(operators.length()));
}
public static int getRandomNumber() {
return randomGenerator.nextInt(100);
}
public static String createEquation() {
//Just for proof of concept, let's do 3 operators
String equation = "";
int numOfOperators = 3;
char operator = ' ';
for (int i = 0; i < numOfOperators; i++) {
equation += getRandomNumber();
equation += getRandomOperator();
}
equation += getRandomNumber();
return equation;
}
public static void main(String[] args) {
String equation = createEquation();
System.out.println(equation);
}
}
I may have time later and come back and address the parentheses issue. For now I just print 'P' where parentheses should be handled.
EDIT
Updated it to handle parentheses. I'm going to paste it down here in case you want to keep it as the old way. Also did a couple tweaks here and there. Note that I didn't handle it matching an exact number of operators when it comes to parenthesis. Which means that if all the open parenthesis weren't closed by the time the loop is done grabbing operators then I append extra parenthesis at the end. Which can result in more than 7 operators. You should probably add logic to either treat a pair of parenthesis as 1 operator or 1 parenthesis as a single operator. Enjoy.
import java.util.Random;
public class Test {
static Random randomGenerator = new Random();
static String operators = "+-*/()";
static int opeatorStringLength = operators.length();
public static char getRandomOperator() {
return operators.charAt(randomGenerator.nextInt(opeatorStringLength));
}
public static int getRandomNumber() {
return randomGenerator.nextInt(100);
}
public static String appendToEquation(String equation, String value1, String value2) {
String temp = equation;
temp += value1;
temp += value2;
return temp;
}
public static String createEquation(int numOfOperators) {
String equation = "";
char operator;
int operand;
int openParenCounter = 0;
for (int i = 0; i < numOfOperators; i++) {
operator = getRandomOperator();
operand = getRandomNumber();
if (operator == '(') {
openParenCounter++;
equation = appendToEquation(equation, Character.toString(operator), Integer.toString(operand));
} else if (operator == ')') {
if (openParenCounter == 0) { //Can't start off with a close parenthesis
openParenCounter++;
equation = appendToEquation(equation, "(", Integer.toString(operand));
} else {
openParenCounter--;
equation = appendToEquation(equation, Integer.toString(operand), Character.toString(operator));
}
} else {
equation = appendToEquation(equation, Integer.toString(operand), Character.toString(operator));
}
}
equation += getRandomNumber();
while (openParenCounter > 0) {
equation += ")";
openParenCounter--;
}
return equation;
}
public static void main(String[] args) {
String equation;
equation = createEquation(7); //The argument passed is the number of operators to use
System.out.println(equation);
}
}

Java Case Switcher

So I'm writing a little return program that switches the case of characters in a string, so HELLo becomes hElLo and hello becomes HeLlO, and aaa becomes AaA. I'm having a bit of trouble though. I'm still new and learning java, so sorry if this breaks rules:
public static String altCase(String text){
String str = "";
for (int i = 0; i <= text.length()-1; i++)
{
char ch = text.charAt(i);
boolean lastIsUpperCase = true;
if(Character.isUpperCase(i-1))
{
lastIsUpperCase = true;
}
else if(Character.isLowerCase(i-1))
{
lastIsUpperCase = false;
}
if(lastIsUpperCase)
{
str += Character.toLowerCase(ch);
}
else if (!lastIsUpperCase)
{
str += Character.toUpperCase(ch);
}
}
return str;
}
You should add the char to your if clause as in:
String str = "";
for (int i = 0; i <= text.length()-1; i++)
{
char ch = text.charAt(i);
if(Character.isUpperCase(ch))
{
str += Character.toLowerCase(ch);
}
else if(Character.isLowerCase(ch))
{
str += Character.toUpperCase(ch);
}
}
return str;
}
I would use a StringBuilder to build up the return value, and you could also use a String.toCharArray() and a for-each loop. Finally, you can test if a character is lower case (or upper case) and then swap the case. Something like,
public static String altCase(String text) {
if (text == null || text.isEmpty()) {
return text;
}
StringBuilder sb = new StringBuilder(text.length());
for (char ch : text.toCharArray()) {
if (Character.isUpperCase(ch)) {
sb.append(Character.toLowerCase(ch));
} else if (Character.isLowerCase(ch)) {
sb.append(Character.toUpperCase(ch));
} else {
sb.append(ch);
}
}
return sb.toString();
}
You could make a char array and then check and swap each element individually. When you are done just pass that char array to a string as argument to make it into a string
char[] word = new char[3];
String str = new String(word);
So I managed to do it.
public static String altCase(String text){
String str = "";
str += Character.toUpperCase(text.charAt(0));
for (int i = 1; i <= text.length()-1; i++)
{
char ch = text.charAt(i);
boolean lastUp = flipFlop(i);
char temp = switcher(ch, lastUp);
str+=temp;
}
return str;
}
public static boolean flipFlop (int i){
boolean bool = true;
if(i==1){
bool = true;
}
else if((i%2)==0)
{
bool = false;
}
else if((i%2)!=0)
{
bool = true;
}
return bool;
}
public static char switcher (char ch, boolean lastUp){
char temp = ch;
if(lastUp){
temp = Character.toLowerCase(ch);
}
else if (lastUp==false){
temp = Character.toUpperCase(ch);
}
return temp;
}
I added a 'flipFlop' method to track the iterations, and the method 'switcher' changes between upper and lower case based on the condition of the last char. (lastUp is true when the last character in the string is uppercase).

Stack problem java. Postfix Evaluation

Hey Guys I'm having a problem when I run my program. In the PostfixEvaluate() Method is where it takes in a string and solves the postfix problem and returns it. Well when I go to run it, I'm getting a bunch of random numbers(some repeated), I'm going crazy because I don't know what else to try and I've spent more time on this than it should normally take.
Heres the PostfixEvaluate Method:
public int PostfixEvaluate(String e){
//String Operator = "";
int number1;
int number2;
int result=0;
char c;
//number1 = 0;
//number2 = 0;
for(int j = 0; j < e.length(); j++){
c = e.charAt(j);
if (c != '+'&& c!= '*' && c!= '-' && c!= '/') {
//if (c == Integer.parseInt(e)) {
s.push(c);
}
else {
number1 = s.pop();
number2 = s.pop();
switch(c) {
case '+':
result = number1 + number2;
break;
case '-':
result = number1 - number2;
break;
case '*':
result = number1 * number2;
break;
case '/':
result = number1 / number2;
break;
} s.push(result);
}
System.out.println(result);
}
return s.pop();
}
public static void main(String[] args) {
Stacked st = new Stacked(100);
String y = new String("(z * j)/(b * 8) ^2");
String x = new String("2 3 + 9 *");
TestingClass clas = new TestingClass(st);
clas.test(y);
clas.PostfixEvaluate(x);
}
}
This is the Stack Class:
public class Stacked {
int top;
char stack[];
int maxLen;
public Stacked(int max) {
top = -1;
maxLen = max;
stack = new char[maxLen];
}
public void push(int result) {
top++;
stack[top] = (char)result;
}
public int pop() {
int x;
x = stack[top];
//top = top - 1;
top--;
return x;
}
public boolean isStackEmpty() {
if(top == -1) {
System.out.println("Stack is empty " + "Equation Good");
return true;
}
else
System.out.println("Equation is No good");
return false;
}
public void reset() {
top = -1;
}
public void showStack() {
System.out.println(" ");
System.out.println("Stack Contents...");
for(int j = top; j > -1; j--){
System.out.println(stack[j]);
}
System.out.println(" ");
}
public void showStack0toTop() {
System.out.println(" ");
System.out.println("Stack Contents...");
for(int j=0; j>=top; j++){
System.out.println(stack[j]);
}
System.out.println(" ");
}
}
It looks to me like you aren't handling spaces at all.
This means that when you put in a space, it is implicitly converting the character space to the ascii value of it (32) when it pops it off the stack during an operation. Also, it looks like you are assuming that all numbers/results will be single digit, and casting from char to int, which is not what you want to do, since that will convert the char to the ascii value of the char, ' ' -> 32, '3' -> 51, etc.
If I were you, I would do this for your loop in PostfixEvaluate:
while(!e.equals("")){
string c;
int space = e.indexOf(' ');
if(space!=-1){
c = e.substring(0,space);
e = e.substring(space+2);
} else{
c = e;
e = "";
}
if (!c.equals("+")&& !c.equal("*") && !c.equals("-") && !c.equals("/")) {
//...
}
and change your stack to hold strings or ints.
The problem is that you are pushing char onto a stack as an int, so you are unintentionally working with the ascii representations of numbers, which is not the actual value of the number.
Instead of this complicated character walking, tokenize the input string using String.split(). Example:
String[] tokens = e.split(" ");
for(String token:tokens){
if (!"+".equals(token) && !"*".equals(token) && !"-".equals(token) && !"/".equals(token)) {
s.push(Integer.parseInt(token));
} else {
....
}
}
You need to split the string into tokens first:
/* Splits the expression up into several Strings,
* all of which are either a number or and operator,
* none of which have spaces in them. */
String [] expressionAsTokens = e.split(" ");
Then you need to make sure you compare Strings, not chars:
//compare strings instead of chars
String token = expressionAsTokens[j];
if (!"+".equals(token) && !"*".equals(token) && !"-".equals(token) && !"/".equals(token)) {
s.push(Integer.parseInt(token));
} else {
//same code as you had before
}
Also, is there any reason you are storing everything as a char array in your Stacked class? Your pop() method returns and integer, yet everything is stored as a char.
For this application, everything should be stored as an integer:
public class Stacked {
int stack[]; // array is of type integer
int top;
int maxLen;
// constructor
public void push() {/*...*/}
public int pop() {/*...*/} //pop returns an int as before
//...
}
One final note: Be careful what order you add and subtract the numbers in. I don't remember if postfix operands are evaluated left first or right first, but make sure you get them in the right order. As you have it now, 2 3 - 4 * would evaluate as 4 * (3 - 2) and I think it should be (2 - 3) * 4. This won't matter with adding and multiplying, but it will with subtracting and dividing.

Categories