Create a binary tree from an algebraic expression - java

I have to create an arithmetic evaluator in Java. To do this I have to parse an algebric expression in binary tree and then calculate and return the result. So for the first step how can I parse an expression in a binary tree? I know the theory but my prob is how to do it in Java. I read the following post
create recursive binary tree
But I'm missing the basic trick or method. I know how to create a node (I have a class with methods like returnNodeValue, isLeaf, isDoubleNode, isSingleNode etc) but I think I'll need a method to insert a node in a binary tree to acheive what I want. Any ideas?

Tree construction for prefix expressions
def insert
Insert each token in the expression from left to right:
(0) If the tree is empty, the first token in the expression (must
be an operator) becomes the root
(1) Else if the last inserted token is an
operator, then insert the token as the left child of the last inserted
node.
(2) Else if the last inserted token is an operand, backtrack up the
tree starting from the last inserted node and find the first node with a NULL
right child, insert the token there. **Note**: don't insert into the last inserted
node.
end def
Let's do an example: + 2 + 1 1
Apply (0).
+
Apply (1).
+
/
2
Apply (2).
+
/ \
2 +
Apply (1).
+
/ \
2 +
/
1
Finally, apply (2).
+
/ \
2 +
/ \
1 1
This algorithm has been tested against - * / 15 - 7 + 1 1 3 + 2 + 1 1
So the Tree.insert implementation is those three rules.
insert(rootNode, token)
//create new node with token
if (isLastTokenOperator)//case 1
//insert into last inserted's left child
else { //case 2
//backtrack: get node with NULL right child
//insert
}
//maintain state
lastInsertedNode = ?, isLastTokenOperator = ?
Evaluating the tree is a little funny, because you have to start from the bottom-right of the tree. Perform a reverse post-order traversal. Visit the right child first.
evalPostorder(node)
if (node == null) then return 0
int rightVal = evalPostorder(node.right)
int leftVal = evalPostorder(node.left)
if(isOperator(node.value))
return rightVal <operator> leftVal
else
return node.value
Given the simplicity of constructing a tree from a prefix expression, I'd suggest using the standard stack algorithm to convert from infix to prefix. In practice you'd use a stack algorithm to evaluate an infix expression.

I think you might be a bit confused about what you are supposed to be doing:
... but I think I'll need a method to insert a node in a binary tree ...
The binary tree you are talking about is actually a parse tree, and it is not strictly a binary tree (since not all tree nodes are binary). (Besides "binary tree" has connotations of a binary search tree, and that's not what you need here at all.)
One you have figured out to parse the expression, the construction of the parse tree is pretty straight-forward. For instance:
Tree parseExpression() {
// ....
// binary expression case:
Tree left = parseExpression();
// parse operator
Tree right = parseExpression();
// lookahead to next operator
if (...) {
} else {
return new BinaryNode(operator, left, right);
}
// ...
}
Note: this is not working code ... it is a hint to help you do your homework.

Related

Recursive generator of random algebraic expressions tree issue

Problem description
I am trying to write a math test for my little son.
Such test must generate a list of random algebraic expressions according to certain rules and check the correctness of solution.
In particular, I want to generate expressions consisting strictly of a given number of operators that are selected from a certain list.
For example generate a list of expression consisting of 3 operators of addition and subtraction in random order like:
12 - (5 + 2) + 2
3 + 4 - 2 + 10
and so on
To represent and calculate the expression, I use the binary expression tree structure.
Each tree consists of either a Leaf or a Node that contains an Operator and two subtrees.
This is a simple recursive structure and I want to work with it only recursively.
No setters in the classes of the tree. I can only use constructors to create a tree.
Leaf class
public final class Leaf implements Expression {
private final int value;
public Leaf(int value) {
this.value = value;
}
// ...
}
Node Class
public final class Node implements Expression {
private final Operator operator;
private final Expression left;
private final Expression right;
public Node(#NotNull Operator operator,
#NotNull Expression left,
#NotNull Expression right) {
this.operator = operator;
this.left = left;
this.right = right;
}
// ...
}
And Operator is a simple Enum type. I simplify my classes for the purposes of this question.
My issue
I am trying to build an expression based on the following rules:
There should be at least one operator in the expression, so my tree always starts from the Node.
I choose a random operator from a given list and increase the number of operators used
While this number less than the given number of operators I construct the left and rights subtree for current Node.
The left subtree can be randomly either a Leaf or Node
The right subtree can also be either a Leaf or Node, but if the left subtree is a Leaf and there are still unused operators, then the right must be a Node.
I wrote such an expression builder:
public class SmartExpressionBuilder {
private final Random random = ThreadLocalRandom.current();
private final List<Operator> allowedOperators;
private final int numberOfOperators;
public SmartExpressionBuilder(List<Operator> allowedOperators, int numberOfOperators) {
this.allowedOperators = allowedOperators;
this.numberOfOperators = numberOfOperators;
}
private int operatorsUsed;
public Expression build() {
operatorsUsed = 0;
return helper();
}
private Expression helper() {
if (operatorsUsed == numberOfOperators) return randomLeaf();
Operator op = randomOperator();
Expression left = random.nextBoolean() ? helper() : randomLeaf();
Expression right = (left instanceof Leaf || random.nextBoolean()) ? helper() : randomLeaf();
return new Node(op, left, right);
}
private Operator randomOperator() {
operatorsUsed++;
return allowedOperators.get(random.nextInt(allowedOperators.size()));
}
private Leaf randomLeaf() {
return new Leaf(random.nextInt(1, 10));
}
public static void main(String[] args) {
final var builder = new SmartExpressionBuilder(List.of(Operator.ADD, Operator.SUB), 4);
IntStream.range(0, 10)
.mapToObj(ignored -> builder.build())
.forEach(exp -> {
System.out.printf("%s = %d%n", exp.infix(), exp.evaluate());
TreePrinter.print(exp);
});
}
}
This works in principle. In the sense that a tree really builds with a given number of operators.
But there's a problem.
I get nodes looks like this:
Node Node
/ \ or / \
Leaf Node Node Leaf
For example my actual expression and tree may looks like this:
4 + 4 - (1 + 3) - 2 = 2
+
4 -
- 2
4 +
1 3
but i never get tree like this:
Node +
/ \ or - +
Node Node 5 2 2 -
6 1
I understand what the essence of the problem is.
In my recursive function, I always go into the left tree first.
And every time my random generates an the Node is in the left subtree, and not the Leaf, recursion dive deeper and deeper int the left subtree until unused operators ends.
This means that if an Node appeared in the left subtree, then Node cannot appear in the right at the same depths of tree.
I broke my brain, but did not figure out how to solve this problem without abandoning the recursive construction of my tree.
I would be very grateful for any ideas how build nodes of this kind
Node
/ \
Node Node
It's going to be very difficult to get balanced trees this way - you have to tune it very carefully for the left tree to probably give you half the operators. I don't think it's worth it.
Instead, I would pick the target number of operators at the top level - that would be a minimum plus some random range to generate larger or smaller expressions - and then randomly assign some of them to each subtree. So you have a recursive call that takes a size parameter; if size==0, generate a leaf, otherwise make a node, and split size-1 into a leftSize and rightSize to pass to the recursive calls.
Here's some rough pseudocode (I don't write much Java these days, but hopefully it makes the algorithm clear)
private Expression build(int size){
if (size == 0) return buildLeaf()
else {
leftSize = randomInt(size-1)
rightSize = size - 1 - leftSize
leftTree = build(leftSize)
rightTree = build(rightSize)
return buildNode(leftTree, rightTree, getRandomOperator())
}
}
Does that make sense and work for you?
I rewritten my method, as Edward Peters suggested.
At each step of recursion, I randomly determine how many Node's will be in the left and right trees (the sum of these numbers at the first step should be equal to the required number of operators in the expression), and return the Leaf if the number of nodes turns out to zero.
It's work just fine.
public Expression build(int numberOfOperators) {
if (numberOfOperators == 0) return randomLeaf();
int leftNodes = random.nextInt(numberOfOperators);
int rightNodes = numberOfOperators - leftNodes - 1;
return new Node(randomOperator(), build(leftNodes), build(rightNodes));
}
One example of resulting expression tree:
5 + 5 - (4 + 7) = -1
- Node
+ + or Node Node
5 5 4 7 Leaf Leaf Leaf Leaf

Validate a Binary Search Tree

I am working on a leetcode problem where I am asked to check whether or not a Binary Search Tree is valid. So far, my solution only passes 58 out 75 test cases. Any pointers on where I went wrong and how to fix it?
Here is the question:
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
Both the left and right subtrees must also be binary search trees.
Example 1:
2
/ \
1 3
Input: [2,1,3]
Output: true
Example 2:
5
/ \
1 4
/ \
3 6
Input: [5,1,4,null,null,3,6]
Output: false
Explanation: The root node's value is 5 but its right child's value is 4.
Here is my Solution:
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidHelper(root);
}
public boolean isValidHelper(TreeNode root)
{
if(root == null)
return true;
isValidHelper(root.left);
if(root.left != null && !(root.left.val < root.val) || root.right != null && !(root.right.val > root.val))
return false;
isValidHelper(root.right);
return true;
}
}
Your program fails in cases like this:
5
3 7
1 6
because you only compare the value at the root of the subtrees.
I don't give a fix on purpose. You will learn more finding that out yourself.

Is it possible to write an algorithm that takes the binary tree T and returns an integer value that represents the height of T

So I'm currently reading Data Structures and Algorithms in Java Sixth Edition and one of the exercises in the book says:
Write algorithm that takes the binary tree T and returns an integer
value that represents the height of T. Recall that the height of a
binary tree is the number of edges between the tree's root and its
furthest leaf. For example, the following tree is of height 3:
The tree looks like this:
A
/ \
B C
/ \ \
D E F
\
G
Now if anyone can give some pointers on how I should start it that would be fantastic because at the moment I'm struggling
with this exercise.
Thank You so much in advance.
Edit: I apologise, I completely forgot to put my pseudocode, here it is:
Algorithm Total_Height (L_subtree, R_subtree, root)
Total_Height (root) {
If (root == null)
Return – 1
Return max (Total_Height( root-> L_subtree), Total_Height (root-> R_subtree))
}
Any remarks or improvements that can be made to this would be greatly appreciated.
To get the "height" of the tree, you have to keep track of the depth you are in right now:
int Tree_Height(root, depth) {
if (root == null) {
return -1;
}
return max(
Tree_Height(root.L_subtree, depth + 1),
Tree_Height(root.R_subtree, depth + 1),
depth
);
}
You need the depth in the max function because at the end of the tree the result will be -1, which will propagate to the top and the overall result from the function will be -1.
If you didn't understand this explanation, try to follow the execution of your program on a piece of paper. This is always helpful when fixing bugs in recursion.

Non recursive floor method for Binary search tree

I have been trying to get this to work but while it works for majority of the input sometimes it gives the wrong output. I have spent some time debugging the code and it seems the problem is when i get a Node that is smaller than the root but bigger than the left node under the root.
How can I traverse the right sub-tree and still return the right key if no node in the right sub-tree is the floor node for that key?
Recall that if you do anything recursively, it can be transformed* into iteration.
Let's consider taking the floor of a well-formed BST, which should simply be the smallest element which is less than or equal to your key in the tree. All we have to do is traverse the tree to get it.
Let's implement it recursively so we can tease out a few important corollaries between iteration and recursion.
// Assuming non-null root node with method declaration
private Node floor(Node root, Key key, Node lowestNode) {
if(key.compareTo(root.getKey()) <= 0) {
if(root.getLeft() != null) {
return floor(root.getLeft(), key, lowestNode);
} else {
return root.compareTo(lowestNode) < 0 ? root : lowestNode;
}
} else {
if(root.getRight() != null) {
lowestRightNode.add(root);
return floor(root.getRight(), key, lowestNode);
} else {
return lowestNode;
}
}
Let's walk through the conditions for success.
If we compare a node to be less than or equal to our key value:
If we have a left child, there's something smaller. Traverse down the left half of the tree.
Otherwise, we're at the floor - which means we're at the node whose value is less than or equal to our key. Return it.
Otherwise (our node has a value greater than our key):
If we have a right child, there's a chance that our work isn't done yet (something's smaller). We'd like to keep it around since we could step off of the tree, so let's store it, then traverse down the right half of the tree.
Otherwise, we've fallen off of the tree. Return the smallest element we've kept track of.
An example may look something like this:
9
/ \
3 14
/ \
1 2
With a key of 12:
Compare with 9. We're larger. Store 9 in our lowest node variable, recurse right.
Compare with 14. We're smaller, but we don't have a left child. We compare the value 14 to 9 and 9 is smaller, so we return the node with 9.
If we want to convert this into iteration, then think about your starting point, your conditional check, and your incrementation steps.
Starting point: A non-null node
Conditional check:
key.compareTo(root.getKey()) <= 0
root.getLeft() != null
continue
root.compareTo(lowestRightNode) < 0 ? root : lowestRightNode
terminal
else
root.getRight() != null
store temp value and continue
return lowestRightNode
terminal
Pay close attention to your continuation conditions, and what other work you'd have to do to keep track of the lowest node you've seen so far (only for the right-hand side, that is).
*: Some recursive operations are more painful to convert than others, of course.

Recursive toString() method in a binary search tree. What is the time complexity for this?

I'm a beginner in Java and looking for some help.
So I've made this binary tree in Java, and I'm supposed to implement a method which sorts all elements in order and convert them into a string. It's supposed to look like ex. "[1, 2, 3, 4]". I used the StringBuilder in order to do this.
My code for the method looks loke this:
/**
* Converts all nodes in current tree to a string. The string consists of
* all elements, in order.
* Complexity: ?
*
* #return string
*/
public String toString() {
StringBuilder string = new StringBuilder("[");
helpToString(root, string);
string.append("]");
return string.toString();
}
/**
* Recursive help method for toString.
*
* #param node
* #param string
*/
private void helpToString(Node<T> node, StringBuilder string) {
if (node == null)
return; // Tree is empty, so leave.
if (node.left != null) {
helpToString(node.left, string);
string.append(", ");
}
string.append(node.data);
if (node.right != null) {
string.append(", ");
helpToString(node.right, string);
}
}
So my question is, how do I calculate the time complexity for this? Also, if there are any suggestions in how to make this method better, I would gladly appreciate it.
The easiest answer is: O(n). You visit every node once and do one (a) amount of work. The calculation would go like
O(a*n)
and because we ignore constant factors, the simple answer would be
O(n)
But. One could also argue, your doing just a little bit more: you return null each time you visit a place where there is no leaf. This again is one (b) amount of work to be done.
Let's call those invisible leaves for a moment. Following this idea, every value in the tree is a node which has one or two invisible leafs.
So now, we have the following to do (for each node):
a | if a node has two child nodes
a + b | if a node has one child node
a + 2b | if a node has no child node.
for a worst case binary tree (totally unbalanced), we have (n-1) nodes with one child node and one node with no child node:
"1"
\
"2"
\
"3"
\
"4"
And so, the calculation is
(n-1)*(a+b) + b
<=> an + bn - a - b + b
<=> n(a+b) + b
=> O(an + bn) // we ignore `+ b` because we always look at really big n's
Fortunately, even in a worst case time scenario, complexity is still linear. Only the constant is higher than in the easy answer. In most cases - usually when Big-O is needed to compare algorithms - we even ignore the factor and we're happy to say, that the algorithms time complexity is linear (O(n)).
The time complexity is O(n) since you are visiting every node once. You cannot do any better than that in order walk the tree.
Time complexity is linear in the number of nodes in the tree: you are visiting each node exactly once.

Categories