ExpressionTree: Postfix to Infix - java

I am having problems getting my toString() method to work and print out parenthesis. Within my infix notation. For example, right now if I enter 12+3* it will print out 1 + 2 * 3. I would like it to print out ((1+2) *3).
Also, I would like my expression tree to be built when it contains a space within the input. For example, right now if I enter 12+ it works, but I want to be able to enter 1 2 + and it still work. Any thoughts?
P.S. Ignore my evaluate method I haven't implemented it yet!
// Java program to construct an expression tree
import java.util.EmptyStackException;
import java.util.Scanner;
import java.util.Stack;
import javax.swing.tree.TreeNode;
// Java program for expression tree
class Node {
char ch;
Node left, right;
Node(char item) {
ch = item;
left = right = null;
}
public String toString() {
return (right == null && left == null) ? Character.toString(ch) : "(" + left.toString()+ ch + right.toString() + ")";
}
}
class ExpressionTree {
static boolean isOperator(char c) {
if ( c == '+' ||
c == '-' ||
c == '*' ||
c == '/'
) {
return true;
}
return false;
}
// Utility function to do inorder traversal
public void inorder(Node t) {
if (t != null) {
inorder(t.left);
System.out.print(t.ch + " ");
inorder(t.right);
}
}
// Returns root of constructed tree for given
// postfix expression
Node constructTree(char postfix[]) {
Stack<Node> st = new Stack();
Node t, t1, t2;
for (int i = 0; i < postfix.length; i++) {
// If operand, simply push into stack
if (!isOperator(postfix[i])) {
t = new Node(postfix[i]);
st.push(t);
} else // operator
{
t = new Node(postfix[i]);
// Pop two top nodes
// Store top
t1 = st.pop(); // Remove top
t2 = st.pop();
// make them children
t.right = t1;
t.left = t2;
// System.out.println(t1 + "" + t2);
// Add this subexpression to stack
st.push(t);
}
}
// only element will be root of expression
// tree
t = st.peek();
st.pop();
return t;
}
public static void main(String args[]) {
Scanner input = new Scanner(System.in);
/*boolean keepgoing = true;
while (keepgoing) {
String line = input.nextLine();
if (line.isEmpty()) {
keepgoing = false;
} else {
Double answer = calculate(line);
System.out.println(answer);
}
}*/
ExpressionTree et = new ExpressionTree();
String postfix = input.nextLine();
char[] charArray = postfix.toCharArray();
Node root = et.constructTree(charArray);
System.out.println("infix expression is");
et.inorder(root);
}
public double evaluate(Node ptr)
{
if (ptr.left == null && ptr.right == null)
return toDigit(ptr.ch);
else
{
double result = 0.0;
double left = evaluate(ptr.left);
double right = evaluate(ptr.right);
char operator = ptr.ch;
switch (operator)
{
case '+' : result = left + right; break;
case '-' : result = left - right; break;
case '*' : result = left * right; break;
case '/' : result = left / right; break;
default : result = left + right; break;
}
return result;
}
}
private boolean isDigit(char ch)
{
return ch >= '0' && ch <= '9';
}
private int toDigit(char ch)
{
return ch - '0';
}
}

Why you use inorder()? root.toString() returns exactly what you want, "((1+2)*3)"
Spaces you can skip at start of loop:
for (int i = 0; i < postfix.length; i++) {
if (postfix[i] == ' ')
continue;
...

Change main like this.
Scanner input = new Scanner(System.in);
String postfix = input.nextLine();
char[] charArray = postfix.replace(" ", "").toCharArray();
Node root = constructTree(charArray);
System.out.println("infix expression is");
System.out.println(root);

Related

Parse Boolean Expression in Java

Given an arbitrary number of TextField inputs (t1, t2, t3, ...) and a custom boolean string input from a JtextArea, I need to check if lines in a file match the custom boolean expression. It needs to support nested parentheses.
Example:
User enters "str1" into t1 , "str2" into t2, "str3" into t3, "str4" into t4, "str5" into t5.
User enters the following into the JTextArea for the custom boolean:
"not ((t1 and not t3) or (t4 and t2)) or t5"
Then based on these inputs, I must filter a file and return lines in the file that match the custom boolean based on a "contains" relationship (e.g. "t1 and not t3" means a line must contain the string t1 and not contain the string t3).
For example a file with the following two lines:
str 5
str4 str2
The filter would only return str5 because it is the only line that matches the custom boolean.
I am having trouble even getting started. I have tried to think of a recursive solution but couldn't come up with anything. Also I tried non-recursive solutions but can't come up with anything either.
There is also the problem of the end result boolean needing to take in a parameter (each line in the file). I thought of maybe producing a sequence of operations to perform rather than a boolean that somehow takes in a parameter. But I can't figure out how to get this sequence in the first place.
Here is what I have now. It is very bad and I am thinking of scrapping this approach.
public class CustomInputParser {
private ArrayList<String> pairs;
private String inp;
private HashMap<Integer,String> atomMap;
public CustomInputParser() {
this.pairs = null;
this.inp = "";
this.atomMap = new HashMap<Integer,String>();
}
public void findAtoms() {
int i = 0;
for(String s : this.pairs) {
String[] indices = s.split(",");
int begin = Integer.valueOf(indices[0]);
int end = Integer.valueOf(indices[1]);
if(!inp.substring(begin+1, end).contains("(")) {
this.pairs.set(i, this.pairs.get(i) + ",#");
}
i++;
}
}
public void computeAtoms() {
int i = 0;
for(String s : this.pairs) {
if(s.contains(",#")) {
String[] indices = s.split(",");
int begin = Integer.valueOf(indices[0]);
int end = Integer.valueOf(indices[1]);
//this.pairs.set(i,this.pairs.get(i).replace(",a", ""));
this.pairs.set(i, this.pairs.get(i) + ","+inp.substring(begin+1, end));
this.atomMap.put(begin,this.pairs.get(i).split(",")[3]+"#"+String.valueOf(end));
}
i++;
}
System.out.println(this.pairs.toString());
System.out.println(this.atomMap.toString());
}
public void replaceAtoms() {
int i = 0;
for(String s : this.pairs) {
if(!(s.contains("o") || s.contains("a") || s.contains("n"))) {
String[] indices = s.split(",");
int begin = Integer.valueOf(indices[0])+1;
int end = Integer.valueOf(indices[1]);
for(int j = begin; j < end; j++) {
if(inp.charAt(j) == '(') {
if(atomMap.containsKey(j)) {
this.pairs.set(i, this.pairs.get(i) + ","+j+"#"+atomMap.get(j).split("#")[1]+">"+atomMap.get(j).split("#")[0]);
}
else {
this.pairs.set(i,"!"+ this.pairs.get(i));
}
}
}
}
i++;
}
System.out.println(this.pairs.toString());
}
public ArrayList<String> getPairs(String str){
this.inp = str;
ArrayList<String> res = new ArrayList<String>();
char[] arr = str.toCharArray();
Stack<Integer> s = new Stack<Integer>();
for(int i = 0; i < arr.length; i++) {
if(arr[i] == '(') {
s.push(i);
}
if(arr[i] == ')') {
if(s.empty()) {
return null;
}
else {
Integer start = s.pop();
Integer end = Integer.valueOf(i);
res.add(start.toString() + "," + end.toString());
}
}
}
if(!s.empty()) {
return null;
}
this.pairs = res;
return res;
}
public static void main(String[] args) {
String x = "((not t1 and ((not t2 or t4) or (t3 or t4))) or (t5 and not t6)) and t7";
x = x.replace("not", "n").replace("and","a").replace("or", "o").replace("t", "").replace(" ", "");
System.out.println(x);
CustomInputParser c = new CustomInputParser();
System.out.println(c.getPairs(x).toString());
c.findAtoms();
c.computeAtoms();
c.replaceAtoms();
}
}
The first step is to tokenize the input. Define
enum Token {VAR, LP, RP, NOT, AND, OR, END}
LP and RP are parentheses. Now define a tokenizer class that looks something like this:
class Tokenizer {
Tokenizer(String input) {...}
void reset() {...}
Token getNext() {...}
String getVarName() {...}
}
Calling getNext() on your example in a loop should return
LP LP NOT VAR AND LP LP NOT VAR OR VAR RP OR LP VAR OR VAR RP RP RP OR LP VAR AND NOT VAR RP RP AND VAR END
Calling getVarName() immediately after a VAR has been returned by getNext() gives you the name of the variable (e.g. "t42").
There are many ways to implement little scanners like this. You should do this first and make sure it's bulletproof by testing. Trying to build a parser on top of a flaky scanner is torture.
As I said in comments, I'd consider recursive descent parsing. If you have a suitable grammar, writing an RD parser is a very short step as the Dragon Book (also mentioned above) shows.
A reasonable grammar (using tokens as above) is
Expr -> Term AND Term
| Term OR Term
| Term END
Term -> NOT Term
| Opnd
Opnd -> VAR
| LP Expr RP
For example, here is how you'd get started. It shows the first rule converted to a function:
class Evaluator {
final Tokenizer tokenizer = ...; // Contains the expression text.
final Map<String, Boolean> env = ... // Environment: variables to values.
Token lookAhead; // Holds the token we're parsing right now.
Evaluator(Tokenizer tokenizer, Map<String, Boolean> env) { ... }
void advance() {
lookAhead = tokenizer.getNext();
}
boolean expr() {
boolean leftHandSide = term(); // Parse the left hand side recursively.
Token op = lookAhead; // Remember the operator.
if (op == Token.END) return leftHandSide; // Oops. That's all.
advance(); // Skip past the operator.
boolean rightHandSide = term(); // Parse the right hand side recursively.
if (op == Token.AND) return leftHandSide && rightHandSide; // Evaluate!
if (op == Token.OR) return leftHandSide || rightHandSide;
dieWithSyntaxError("Expected op, found " + op);
}
boolean term() {...}
boolean opnd() {...}
}
The environment is used when a VAR is parsed. Its boolean value is env.get(tokenizer.getVarName()).
So to process the file, you'll
For each line
For each variable tX in the expression
See if the line contains the string tX is bound to in its text field.
If so, put the mapping tX -> true in the environment
else put tX -> false
Reset the tokenizer
Call Evaluator.evaluate(tokenizer, environment)
If it returns true, print the line, else skip it.
This is the simplest approach I can think of. About 150 lines. Many optimizations are possible.
Added
Well since I can no longer take away the thrill of discovery, here is my version:
import static java.lang.Character.isDigit;
import static java.lang.Character.isWhitespace;
import java.util.HashMap;
import java.util.Map;
import static java.util.stream.Collectors.toMap;
public class TextExpressionSearch {
enum Token { VAR, LP, RP, NOT, AND, OR, END }
static class Tokenizer {
final String input;
int pos = 0;
String var;
Tokenizer(String input) {
this.input = input;
}
void reset() {
pos = 0;
var = null;
}
String getRead() {
return input.substring(0, pos);
}
Token getNext() {
var = null;
while (pos < input.length() && isWhitespace(input.charAt(pos))) {
++pos;
}
if (pos >= input.length()) {
return Token.END;
}
int start = pos++;
switch (input.charAt(start)) {
case 't':
while (pos < input.length() && isDigit(input.charAt(pos))) {
++pos;
}
var = input.substring(start, pos);
return Token.VAR;
case '(':
return Token.LP;
case ')':
return Token.RP;
case 'n':
if (input.startsWith("ot", pos)) {
pos += 2;
return Token.NOT;
}
break;
case 'a':
if (input.startsWith("nd", pos)) {
pos += 2;
return Token.AND;
}
break;
case 'o':
if (input.startsWith("r", pos)) {
pos += 1;
return Token.OR;
}
break;
}
throw new AssertionError("Can't tokenize: " + input.substring(start));
}
}
static class Evaluator {
final Tokenizer tokenizer;
final Map<String, Boolean> env;
Token lookAhead;
Evaluator(Tokenizer tokenizer, Map<String, Boolean> env) {
this.tokenizer = tokenizer;
this.env = env;
advance();
}
boolean die(String msg) {
throw new AssertionError(msg + "\nRead: " + tokenizer.getRead());
}
void advance() {
lookAhead = tokenizer.getNext();
}
void match(Token token) {
if (lookAhead != token) {
die("Expected " + token + ", found " + lookAhead);
}
advance();
}
boolean evaluate() {
boolean exprVal = expr();
match(Token.END);
return exprVal;
}
boolean expr() {
boolean lhs = negated();
switch (lookAhead) {
case AND:
advance();
return negated() && lhs;
case OR:
advance();
return negated() || lhs;
case END:
return lhs;
}
return die("Expected expr, found " + lookAhead);
}
boolean negated() {
switch (lookAhead) {
case NOT:
advance();
return !negated();
default:
return operand();
}
}
boolean operand() {
switch (lookAhead) {
case VAR:
if (!env.containsKey(tokenizer.var)) {
die("Undefined variable: " + tokenizer.var);
}
boolean varVal = env.get(tokenizer.var);
advance();
return varVal;
case LP:
advance();
boolean exprVal = expr();
match(Token.RP);
return exprVal;
}
return die("Expected operand, found " + lookAhead);
}
}
public static void main(String [] args) {
String expr = "((not t1 and ((not t2 or t4) or (t3 or t4))) or (t5 and not t6)) and t7";
Map<String, String> bindings = new HashMap<>();
bindings.put("t1", "str1");
bindings.put("t2", "str2");
bindings.put("t3", "str3");
bindings.put("t4", "str4");
bindings.put("t5", "str5");
bindings.put("t6", "str6");
bindings.put("t7", "str7");
String [] lines = {"str5 str7", "str4 str2"};
Tokenizer tokenizer = new Tokenizer(expr);
for (String line : lines) {
Map<String, Boolean> env =
bindings.entrySet().stream()
.collect(toMap(e -> e.getKey(), e -> line.contains(e.getValue())));
tokenizer.reset();
if (new Evaluator(tokenizer, env).evaluate()) {
System.out.println(line);
}
}
}
}
You can define a parser that returns a Predicate<String> that tests if a given string satisfies a conditional expression.
static Predicate<String> parse(String s, Map<String, String> map) {
return new Object() {
String[] tokens = Pattern.compile("[()]|[a-z][a-z0-9]*")
.matcher(s).results()
.map(MatchResult::group)
.toArray(String[]::new);
int length = tokens.length;
int index = 0;
String token = get();
String get() {
return token = index < length ? tokens[index++] : null;
}
boolean eat(String expect) {
if (expect.equals(token)) {
get();
return true;
}
return false;
}
Predicate<String> identifier() {
String id = token;
return s -> {
String value = map.get(id);
if (value == null)
throw new RuntimeException(
"identifier '" + id + "' undefined");
return s.contains(value);
};
}
Predicate<String> factor() {
boolean not = false;
Predicate<String> p;
if (eat("not"))
not = true;
switch (token) {
case "(":
get();
p = expression();
if (!eat(")"))
throw new RuntimeException("')' expected");
break;
case ")": case "not": case "and": case "or":
throw new RuntimeException("syntax error at '" + token + "'");
default:
p = identifier();
get();
break;
}
if (not)
p = p.negate();
return p;
}
Predicate<String> term() {
Predicate<String> p = factor();
while (eat("and"))
p = p.and(factor());
return p;
}
Predicate<String> expression() {
Predicate<String> p = term();
while (eat("or"))
p = p.or(term());
return p;
}
Predicate<String> parse() {
Predicate<String> p = expression();
if (token != null)
throw new RuntimeException("extra tokens string");
return p;
}
}.parse();
}
test case:
#Test
public void testParse() {
String s = "not ((t1 and not t3) or (t4 and t2)) or t5";
Map<String, String> map = new HashMap<>(Map.of(
"t1", "str1",
"t2", "str2",
"t3", "str3",
"t4", "str4",
"t5", "str5"));
Predicate<String> p = parse(s, map);
assertTrue(p.test("str5"));
assertTrue(p.test("str3"));
assertTrue(p.test("str1 str3"));
assertFalse(p.test("str1"));
assertFalse(p.test("str2 str4"));
// you can change value of variables.
assertFalse(p.test("str1 FOO"));
map.put("t5", "FOO");
assertTrue(p.test("str1 FOO"));
}
syntax:
expression = term { "or" term }
term = factor { "and" factor }
factor = [ "not" ] ( "(" expression ")" | identifier )
identifier = letter { letter | digit }
letter = "a" | "b" | ... | "z"
digit = "0" | "1" | ... | "9"
For posterity, here is my shunting yard solution which includes input validation:
public class CustomInputParser {
private Stack<Character> ops;
private LinkedList<Character> postFix;
private HashMap<Character, Integer> precedence;
private Stack<Boolean> eval;
private HashMap<Integer, String> termsMap;
private String customBool;
public CustomInputParser(HashMap<Integer, String> tMap, String custBool) {
this.ops = new Stack<Character>();
this.eval = new Stack<Boolean>();
this.postFix = new LinkedList<Character>();
this.termsMap = tMap;
this.customBool = custBool;
this.precedence = new HashMap<Character, Integer>();
precedence.put('n', 1);
precedence.put('a', 2);
precedence.put('o',3);
precedence.put('(', 4);
}
private int inToPost() {
char[] expr = convertToArr(this.customBool);
char c;
for(int i = 0; i < expr.length; i++) {
c = expr[i];
if(isOp(c)) {
if(processOp(c) != 0) return -1;
}
else {
if(!Character.isDigit(c)) {
return -1;
}
//I made the mistake of using a queue of Characters for postfix initially
//This only worked for up to 9 operands (multi digit would add mutiple chars to
// postfix for a single reference.
//This loops is a lazy workaround:
// 1. get the string of the reference (e.g. "11")
// 2. convert it to int
// 3. store the char value of the int in postfix
// 4. when evaluating operands in postfix eval, convert char back to int to get the termsMap key
String num = "";
while(i < expr.length) {
if(!Character.isDigit(expr[i])) {
i--;
break;
}
c = expr[i];
num += c;
i++;
}
int j = Integer.valueOf(num);
c = (char) j;
postFix.offer(c); //enqueue
}
}
while(!ops.empty()) {
if(ops.peek() == '(')return -1; //no matching close paren for the open paren
postFix.offer(ops.pop()); //pop and enqueue all remaining ops from stack
}
return 0;
}
private boolean isOp(char c) {
if(c == '(' || c == ')' || c =='n' || c=='a' || c=='o') {
return true;
}
return false;
}
private int processOp(char c) {
if (ops.empty() || c == '(') {
ops.push(c);
}
else if(c == ')') {
while(ops.peek() != '(') {
postFix.offer(ops.pop()); //pop and equeue ops wrapped in parens
if(ops.empty()) return -1; //no matching open paren for the close paren
}
ops.pop(); // don't enqueue open paren, just remove it from stack
}
else if(precedence.get(c) > precedence.get(ops.peek())) {
postFix.offer(ops.pop()); //pop and enqueue the higher precedence op
ops.push(c);
}
else {
ops.push(c);
}
return 0;
}
public boolean evaluate(String s) {
while(!postFix.isEmpty()) {
char c = postFix.poll();
boolean op1, op2;
switch(c) {
case 'n':
op1 = eval.pop();
eval.push(!op1);
break;
case 'a':
op1 = eval.pop();
op2 = eval.pop();
eval.push(op1 && op2);
break;
case 'o':
op1 = eval.pop();
op2 = eval.pop();
eval.push(op1 || op2);
break;
default:
int termKey = (int) c;
String term = this.termsMap.get(termKey);
eval.push(s.contains(String.valueOf(term)));
break;
}
}
return eval.pop();
}
private char[] convertToArr(String x) {
x = x.replace("not", "n").replace("and","a").replace("or", "o").replace("t", "").replace(" ", "");
return x.toCharArray();
}
public static void main(String[] args) {
String customBool = "(t1 and not (t2 and t3)) or (t4 and not t5)";
HashMap<Integer,String> termsMap = new HashMap<Integer, String>();
termsMap.put(1,"str1");
termsMap.put(2,"str2");
termsMap.put(3,"str3");
termsMap.put(4,"str4");
termsMap.put(5,"str5");
CustomInputParser c = new CustomInputParser(termsMap, customBool);
if(c.inToPost() != 0) {
System.out.println("invalid custom boolean");
}
else {
System.out.println(c.evaluate("str1str5"));
}
}
}

Algorithm for rock, paper, scissors game

So this is a slightly different take on the age old rock, paper, scissors java example. In this situation, the user enters the input (that I'm assuming is valid, i.e. uses only combinations of R,P, & S, and has matching parenthesis, also no spaces) like for example, (R&S) the output is R because Rock beats Scissors, or ((R&S)&(P&R)) outputs P.
Now so far I have code (below) that can split the strings, iterate through and get the letters used into a list, because my idea was just to read from left to right, evaluating until I get to the end but at this point I'm stumped because what would be a good way to keep track of all the "previous" results. Would I need another empty list? Also using cases doesn't seem viable since the input can be long and also completely random combination of R,P, and S. Any advice is appreciated!
import java.util.ArrayList;
import java.util.Scanner;
public class RPS {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
str = str.replaceAll("\\(", "").replaceAll("\\)","");
String inputs[] = str.split("&");
ArrayList<Object> list = new ArrayList<>();
for (int i = 0; i < inputs.length; i++){
if (inputs[i].substring(0, 1).contains("R")) {
list.add(inputs[i]);
} else if (inputs[i].substring(0, 1).contains("S")) {
list.add(inputs[i]);
} else if (inputs[i].substring(0, 1).contains("P")) {
list.add(inputs[i]);
}
}
for (int i = 0; i < list.size(); i++){
if (list.contains("R") && list.contains("S")){ //ex. if the input was "(R&S)"
System.out.println("R");
break;
}
}
}
}
One way to solve this would be to write a recursive evaluate function. It would take a string as input, with the base case being a single character R, P, or S. Otherwise, it would split the string on the top-level ampersand, and recursively evaluate the string to the left and right of the ampersand, and use the returned characters to determine the result. The top-level ampersand could be found as the ampersand occurring not within a set of parentheses (not counting any outermost redundant parentheses if they exist).
For example, here's an implementation in Java.
import java.util.Stack;
public class RPS {
// Normalize string by removing surrounding parentheses that are redundant.
private static String normalize(String s) {
// First, count the number of leading open parentheses.
int leading = 0;
for (int i = 0; i < s.length(); ++i) {
if (s.charAt(i) != '(')
break;
++leading;
}
if (leading > 0) {
// For each closing parenthesis, compute the position of the
// matching opening parenthesis. The set of trailing parentheses
// paired with leading parentheses are redundant.
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (c == '(') {
stack.push(i);
} else if (c == ')') {
int j = stack.pop();
if (j < leading && j + i + 1 == s.length())
return s.substring(j + 1, s.length() - j - 1);
}
}
}
return s;
}
private static char evaluate(String s) {
s = normalize(s);
// A single character evaluates to itself
if (s.length() == 1)
return s.charAt(0);
// Find the position of the top-level ampersand, which is the ampersand
// occurring outside matched pairs of parentheses.
int depth = 0;
int position = -1;
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (c == '(')
depth += 1;
else if (c == ')')
depth -= 1;
else if (depth == 0 && c == '&') {
position = i;
break;
}
}
// Otherwise, split on the top-level ampersand and evaluate the left
// and right sides.
char left = evaluate(s.substring(0, position));
char right = evaluate(s.substring(position + 1));
// Return the winner
if (left == right)
return left;
switch (left) {
case 'R':
return right == 'P' ? 'P' : 'R';
case 'P':
return right == 'S' ? 'S' : 'P';
case 'S':
return right == 'R' ? 'R' : 'S';
default:
throw new RuntimeException();
}
}
public static void main(String[] args) {
System.out.println(evaluate("((R&S)&(P&R))"));
System.out.println(evaluate("(R&S)&(P&R)"));
System.out.println(evaluate("(R)"));
System.out.println(evaluate("((((R&P))&((S))))"));
System.out.println(evaluate("((R&S)&R)"));
System.out.println(evaluate("S"));
System.out.println(evaluate("(((R&P)&(S&P))&(P&R))"));
}
}
Output:
P
P
R
S
R
S
S
If you process your input and convert it to reverse polish notation, you can use a Stack to hold the values and the operators.
Here's what I mean. Take your simple input.
(R&S)
On a Stack, it would look like:
R
S
&
The stack should always start with two values and one operator.
Let's take your more complicated example.
((R&S)&(P&R))
On a Stack, it would look like:
R
S
&
P
R
&
&
You'd replace the RS& on the Stack with the result. Then you'd replace the PR& on the Stack with the result. The final result would be processed with the last & operator.
One way to solve this is to first parse the string into a tree where nodes are either 1) a character or 2) a group of children nodes representing items in parentheses. Then call a recursive evaluation function on the tree.
For example, here's an implementation in Java that has error checking and support for white spaces (which are ignored), followed by my initial prototype in Python, which is shorter, but does not include error checking nor support for white spaces.
Java
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
public class RPS {
private static class Node {
Character data = null;
List<Node> children = null;
}
private static Node parse(Queue<Character> tokens) {
// WARN: Destructively modifies input
char token = tokens.remove();
Node node = new Node();
if (token == '(') {
node.children = new ArrayList<Node>();
while (tokens.peek() != ')') {
node.children.add(parse(tokens));
}
char c = tokens.remove();
if (c != ')')
throw new RuntimeException();
} else if (token == ')') {
throw new RuntimeException();
} else {
node.data = token;
}
return node;
}
private static char _evaluate(Node tree) {
if (tree.data != null) {
return tree.data;
} else if (tree.children.size() == 1) {
return _evaluate(tree.children.get(0));
} else {
char left = _evaluate(tree.children.get(0));
if (!tree.children.get(1).data.equals('&'))
throw new RuntimeException();
char right = _evaluate(tree.children.get(2));
// Return the winner
if (left == right)
return left;
switch (left) {
case 'R':
return right == 'P' ? 'P' : 'R';
case 'P':
return right == 'S' ? 'S' : 'P';
case 'S':
return right == 'R' ? 'R' : 'S';
default:
throw new RuntimeException();
}
}
}
private static Set<Character> VALID_CHARS =
new HashSet<Character>() {{
add('(');
add(')');
add('&');
add('R');
add('P');
add('S');
}};
public static char evaluate(String s) {
Queue<Character> tokens = new LinkedList<Character>();
tokens.add('(');
for (int i = 0; i < s.length(); ++i) {
char c = Character.toUpperCase(s.charAt(i));
if (Character.isWhitespace(c))
continue;
if (!VALID_CHARS.contains(c))
throw new RuntimeException();
tokens.add(c);
}
tokens.add(')');
Node tree = parse(tokens);
char c = _evaluate(tree);
return c;
}
public static void main(String[] args) {
System.out.println(evaluate("((R&S)&(P&R))")); // P
System.out.println(evaluate("(R&S)&(P&R)")); // P
System.out.println(evaluate("( R )")); // R
System.out.println(evaluate("((((R&P))&((S))))")); // S
System.out.println(evaluate("((R&S)&R)")); // R
System.out.println(evaluate("S")); // S
System.out.println(evaluate("(((R&P)&(S&P))&(P&R))")); // S
}
}
Python
from collections import deque
from typing import Union
def parse(tokens: deque):
# WARN: Destructively modifies input
token = tokens.popleft()
if token == '(':
result = []
while tokens[0] != ')':
result.append(parse(tokens))
tokens.popleft() # closing ')'
return result
else:
return token
def _evaluate(tree: Union[list, str]):
if type(tree) != list:
return tree
elif len(tree) == 1:
return _evaluate(tree[0])
else:
left = _evaluate(tree[0])
right = _evaluate(tree[2])
pair = left + right
lookup = {
'RP': 'P', 'PR': 'P', 'PP': 'P',
'RS': 'R', 'SR': 'R', 'RR': 'R',
'PS': 'S', 'SP': 'S', 'SS': 'S',
}
return lookup[pair]
def evaluate(s: str):
tokens = deque(f'({s})')
tree = parse(tokens)
return _evaluate(tree)
# Example usage
print(evaluate('((R&S)&(P&R))')) # P
print(evaluate('(R&S)&(P&R)')) # P
print(evaluate('(R)')) # R
print(evaluate('((((R&P))&((S))))')) # S
print(evaluate('((R&S)&R)')) # R
print(evaluate('S')) # S
print(evaluate('(((R&P)&(S&P))&(P&R))')) # S

Parenthesis creation in the infix expression using stack in java

I need to write a Java program that takes from the standard input a valid Right Parenthesized Infix Expression (RPIE) and outputs the equivalent Full Parenthesized Infix Expression (FPIE). For example, if the input is: a+20)/b-c)53.4-d))) , the output should be ((a+20)/((b-c)(53.4-d))).
I have tried to implement as follows but did not reach the solution. Could anyone help me?
import java.util.Scanner;
import java.util.Stack;
public class ParenthesisCreator {
static private String expression;
private Stack<Character> stack = new Stack<Character>();
public ParenthesisCreator(String input) {
expression = input;
}
public String rtParenthesisInfixToFullParenthesis() {
String postfixString = "";
for (int index = 0; index < expression.length(); ++index) {
char value = expression.charAt(index);
if (value == ')') {
stack.push(')');
stack.push('(');
Character oper = stack.peek();
while (!stack.isEmpty()) {
stack.pop();
postfixString += oper.charValue();
if (!stack.isEmpty())
oper = stack.peek();
}
} else {
postfixString += value;
}
}
return postfixString;
}
public static void main(String[] args) {
System.out.println("Type an expression written in right parenthesized infix: ");
Scanner input = new Scanner(System.in);
String expression = input.next();
// Input: a+20)/b-c)*53.4-d)))
// Desired output is: ((a+20)/((b-c)*(53.4-d)))
ParenthesisCreator convert = new ParenthesisCreator(expression);
System.out.println("This expression writtien in full parenthesized is: \n" + convert.rtParenthesisInfixToFullParenthesis());
}
}
public final class ParenthesisCreator implements Function<String, String> {
private final IntPredicate isOperator;
public ParenthesisCreator() {
this(ch -> ch == '/' || ch == '*' || ch == '+' || ch == '-');
}
public ParenthesisCreator(IntPredicate isOperator) {
this.isOperator = isOperator;
}
#Override
public String apply(String expr) {
Deque<String> stack = new LinkedList<>();
StringBuilder buf = null;
for (int i = 0; i < expr.length(); i++) {
char ch = expr.charAt(i);
if (ch == ')') {
if (buf != null) {
stack.push(buf.insert(0, '(').append(')').toString());
buf = null;
} else if (stack.size() >= 2) {
String two = stack.pop();
String one = stack.pop();
stack.push('(' + one + two + ')');
} else
throw new IllegalArgumentException();
} else if (isOperator.test(ch) && buf == null && !stack.isEmpty())
stack.push(stack.pop() + ch);
else
(buf = buf == null ? new StringBuilder() : buf).append(ch);
}
return String.join("", stack);
}
}
Demo
System.out.println(new ParenthesisCreator().apply("a+20)/b-c)53.4-d)))")); // ((a+20)/((b-c)(53.4-d)))
public class FixExpressionParentheses {
public String fixExpression(String expression) {
String[] tokenArray = expression.split(" ");
Stack<String> operators = new Stack<>();
Stack<String> operands = new Stack<>();
for (String token: tokenArray) {
switch (token) {
case "+", "-", "*", "/", "sqrt" -> operators.push(token);
case ")" -> {
String operator = operators.pop();
String operandTwo = operands.pop();
String operandOne = operands.pop();
String newToken = "( " + operandOne + " " + operator + " "
+ operandTwo + " )";
operands.push(newToken);
}
default -> operands.push(token);
}
}
return operands.pop();
}
}

Converting a Postfix Notation to an ExpressionTree

As it is said in the title I am trying to create a code which converts a postfix notation to an expression tree. Here you can check the constructor :
public byte type; // 0 : operator, 1: operand (a number)
public char operator; // One of '+', '-', '*', '/'
public int operand; // A number
ExpressionTreeNode(byte type){this.type = type; left=right=null;}
and Here is my code :
public static ExpressionTreeNode Postfix2ExpressionTree(String postfixExpr){
Stack s = new Stack<Object>();
ExpressionTreeNode root = new ExpressionTreeNode((byte) 0);
root.operator = postfixExpr.charAt(postfixExpr.length()-1);
String number = "";
for(int i = 0;i<postfixExpr.length()-1;i++){
if(Character.isDigit(postfixExpr.charAt(i)) == true){
number = number + postfixExpr.charAt(i);
if(Character.isDigit(postfixExpr.charAt(i+1)) == false){
ExpressionTreeNode node = new ExpressionTreeNode((byte) 1);
node.operand = Integer.valueOf(number);
node.right = null;
node.left = null;
s.push(node);
number = "";
}
}
if(i == postfixExpr.length()-2){
root.right = (ExpressionTreeNode) s.pop();
root.left =(ExpressionTreeNode) s.pop();
s.push(root);
break;
}
else {
if(postfixExpr.charAt(i) == '+' || postfixExpr.charAt(i) == '*' || postfixExpr.charAt(i) == '-' || postfixExpr.charAt(i) == '/' ){
ExpressionTreeNode node = new ExpressionTreeNode((byte)0);
node.operand = postfixExpr.charAt(i);
node.right = (ExpressionTreeNode) s.pop();
node.left = (ExpressionTreeNode) s.pop();
s.push(node);
}
}
}
return (ExpressionTreeNode) s.pop();
}
I check every character one by one with charAt() method. Simply
1-push every operand into the stack
2-when operator is encountered pop two operand from the stack and assign them to right and left of operator then push the new node to the stack.
3- and finally I push the root to the stack then return it.
No error occurs when I try to run but also it is not working in the right way too. I checked the code many times but I couldn't solve it.If anyone sees the mistake and help me , that would be great.
A postfix expression is parsed from left to right - don't look at postfixExpr.length()-1 before you are there.
Do not create and handle a root node in any special way. It will be top of the stack after the parse.
Here's an error:
node.operand = postfixExpr.charAt(i);
This must be stored in node.operator.
This is how I would implement it:
public interface Entry {
int evaluate();
}
public class Value implements Entry {
private int value;
public Value( int value ){
this.value = value;
}
public int evaluate(){
return value;
}
}
public class Operation implements Entry {
private char operator;
private Entry left;
private Entry right;
public Operation( char operator, Entry left, Entry right ){
this.operator = operator;
this.left = left;
this.right = right;
}
public int evaluate(){
int l = left.evaluate();
int r = right.evaluate();
switch(operator){
case '+':
return l + r;
case '-':
return l - r;
case '*':
return l * r;
case '/':
return l / r;
}
throw new IllegalStateException( "operator " + operator );
}
}
public class Parser {
private Stack<Entry> stack = new Stack<>();
Pattern pat = Pattern.compile( "[-+*/]" );
Scanner scanner;
public void parse( String ex ){
scanner = new Scanner( ex );
while( scanner.hasNext() ){
while( scanner.hasNextInt() ){
stack.push( new Value( scanner.nextInt() ) );
}
while( scanner.hasNext( pat ) ){
char op = scanner.next( pat ).charAt( 0 );
Entry right = stack.pop();
Entry left = stack.pop();
stack.push( new Operation( op, left, right ) );
}
}
}
public Entry get(){
return stack.pop();
}
}
There is absolutely no error handling, so think about adding that.

Java Binary Tree entered in a specific order

I am trying to complete an assignment where I need to write a Java program to take a string from the command line, and implement it as a Binary Tree in a specific order, then get the depth of the binary tree.
For example: "((3(4))7((5)9))"
would be entered as a tree with 7 as the root, 3 and 9 as the children, and 4 as a right child of 3, and 5 as a left child of 9.
My code is below.. The problem I am having is that, because I am basing my checks off of finding a right bracket, I am unsure how to get the elements correctly when they are not directly preceding the brackets, such as the 3 in the above string. Any direction would be greatly appreciated..
class Node {
int value;
Node left, right;
}
class BST {
public Node root;
// Add Node to Tree
public void add(int n) {
if (root == null) {
root = new Node( );
root.value = n;
}
else {
Node marker = root;
while (true) {
if (n < marker.value) {
if (marker.left == null) {
marker.left = new Node( );
marker.left.value = n;
break;
} else {
marker = marker.left;
}
} else {
if (marker.right == null) {
marker.right = new Node( );
marker.right.value = n;
break;
} else {
marker = marker.right;
}
}
}
}
} // End ADD
//Find Height of Tree
public int height(Node t) {
if (t.left == null && t.right == null) return 0;
if (t.left == null) return 1 + height(t.right);
if (t.right == null) return 1 + height(t.left);
return 1 + Math.max(height(t.left), height(t.right));
} // End HEIGHT
// Check if string contains an integer
public static boolean isInt(String s) {
try {
Integer.parseInt(s);
}
catch(NumberFormatException e) {
return false;
}
return true;
} // End ISINT
public int elementCount(String[] a) {
int count = 0;
for (int i = 0; i < a.length; i++) {
if (isInt(a[i])) count++;
}
return count;
}
} // End BST Class
public class Depth {
public static void main(String[] args) {
String[] a = args[0].split(" ");
BST tree = new BST();
int[] bcount = new int[10];
int[] elements = new int[10];
int x = 0, bracketcount = 0;
// Display entered string
System.out.print("Entered Format: ");
for (int j=0; j < a.length; j++) {
System.out.print(a[j]);
}
for (int i=0; i < a.length; i++) {
char c = a[i].charAt(0);
switch (c)
{
case '(':
bracketcount++;
break;
case ')':
if (isInt(a[i-1])) {
bcount[x] = bracketcount--;
elements[x++] = Integer.parseInt(a[i-1]);
}
break;
case '1':
case '7':
default : // Illegal character
if ( (a[i-1].charAt(0) == ')') && (a[i+1].charAt(0) == '(') ) {
bcount[x] = bracketcount;
elements[x++] = Integer.parseInt(a[i]);
}
break;
}
}
System.out.println("\nTotal elements: " + tree.elementCount(a));
// Display BracketCounts
for (int w = 0; w < x; w++) {
System.out.print(bcount[w] + " ");
}
System.out.println(" ");
// Display Elements Array
for (int w = 0; w < x; w++) {
System.out.print(elements[w] + " ");
}
System.out.println("\nDepth: " + tree.height(tree.root));
// Build the tree
for (int y = 0; y < x-1; y++) {
for (int z = 1; z < tree.height(tree.root); z++) {
if (bcount[y] == z) {
tree.add(elements[y]);
}
}
}
} // End Main Function
public static boolean isInt(String s) {
try {
Integer.parseInt(s);
}
catch(NumberFormatException e) {
return false;
}
return true;
}
} // End Depth Class
I would do a couple of statements to get access to a tree with that kind of shape:
For input string : input= "((3(4))7((5)9))"
You could do :
public class Trial {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String input = "((3(4))7((5)9))";
String easier = input.replaceAll("\\(\\(", "");
String evenEasier = easier.replaceAll("\\)\\)", "");
System.out.println(evenEasier);
int firstVal = Integer.parseInt(evenEasier.substring(0, 1));
int firstBracketVal = Integer.parseInt(evenEasier.substring(2, 3));
int middleVal = Integer.parseInt(evenEasier.substring(3, 4));
int secondBracketVal = Integer.parseInt(evenEasier.substring(4,5));
int lastVal = Integer.parseInt(evenEasier.substring(6));
System.out.println("First Val:"+firstVal);
System.out.println("First bracket Val:"+firstBracketVal);
System.out.println("Middle Val:"+middleVal);
System.out.println("Second Bracket Val:"+secondBracketVal);
System.out.println("Last Val:"+lastVal);
}
}
This however would only ever work for entries in that specific format, if that were to change, or the length of the input goes up - this would work a bit or break.....If you need to be able to handle more complicated trees as input in this format a bit more thought would be needed on how to best handle and convert into your internal format for processing.
pseudocode:
function getNode(Node)
get one char;
if (the char is "(")
getNode(Node.left);
get one char;
end if;
Node.value = Integer(the char);
get one char;
if (the char is "(")
getNode(Node.right);
get one char;
end if;
//Now the char is ")" and useless.
end function
Before calling this function, you should get a "(" first.
In this method, the framwork of a Node in string is "[leftchild or NULL] value [rightchild or NULL])".
"("is not belong to the Node, but ")" is.

Categories

Resources