Split a binary tree - java

I am trying to split a binary search tree at the root in Java. I have no idea how to go about this. The recursive call is what is mostly confusing me. Below is the pseudocode that I was given. When x is greater than T (the tree to be split), am I going to call split(R.key, R.right, L, R)? Am I on the right track? This is the only function in the project that is confusing me.
Thanks in advance.
void split( int x, bst T, bst L, bst R) /* assuming x is not in T */
{
if T is null, make L and R null
else if x < T.key
set R = T /* all keys at the root and in right subtree are greater than x */
recursively split T's left subtree into L and R’s left subtree
/* some keys in T's left subtree are greater than x, other may be less than x */
else /* x is greater than T.key */
set L = T
recursively split T's right subtree into L's right subtree and R
}

It is important that you must have a binary ordered tree, such that Left < Root < Right for every subtree. Also, there is no node in the left subtree such that node > Root, and no node in the right subtree such that node < Root. Balancing (that all subtrees are same depth +- 1) is not needed.
It is like a dicomotical search; if the value to split by is greater than your current root, you are sure that it is greater than all nodes in the left subtree (because of the previous restriction). So, in order to search which of the nodes of the tree are bigger, you only need to check the nodes to the right. Likewise, if the value to split by is less than the value of root, it is also less than the values of all the nodes of the right subtree, and you must check more finely in the left tree.
In order to see it clearly, I suggest you to draw this tree (no spacing here)
8
4 12
3 6 10 14
1 2 5 7 9 11 13 15
, set several sample split values, and mark which nodes would remain in the new tree.

Related

Print random element from binary tree in O(logn)

Given a binary tree with TreeNode like:
class TreeNode {
int data;
TreeNode left;
TreeNode right;
int size;
}
Where size is the number of nodes in the (left subtree + right subtree + 1).
Print a random element from the tree in O(logn) running time.
Note: This post is different from this one, as it is clearly mentioned that we have a size associated with each node in this problem.
PS: Wrote this post inspired from this.
There is an easy approach which gives O(n) complexity.
Generate a random number in the range of 1 to root.size
Do a BFS or DFS traversal
Stop iterating at random numbered element and print it.
For improving the complexity, we need to create an ordering of our own where we branch at each iteration instead of going sequentially as in BFS and DFS. We can use the size property of each node to decide whether to traverse through the left sub-tree or right sub-tree. Following is the approach:
Generate a random number in the range of 1 to root.size (Say r)
Start traversing from the root node and decide whether to go to left sub-tree, right-subtree or print root:
if r <= root.left.size, traverse through the left sub-tree
if r == root.left.size + 1, print the root (we have found the random node to print)
if r > root.left.size + 1, traverse through the right sub-tree
Essentially, we have defined an order where current node is ordered at (size of left subtree of current) + 1.
Since we eliminate traversing through left or right sub-tree at each iteration, its running time is O(logn).
The pseudo-code would look something like this:
traverse(root, random)
if r == root.left.size + 1
print root
else if r > root.left.size + 1
traverse(root.right, random - root.left.size - 1)
else
traverse(root.left, random)
Following is an implementation in java:
public static void printRandom(TreeNode n, int randomNum) {
int leftSize = n.left == null ? 0 : n.left.size;
if (randomNum == leftSize + 1)
System.out.println(n.data);
else if (randomNum > leftSize + 1)
printRandom(n.right, randomNum - (leftSize + 1));
else
printRandom(n.left, randomNum);
}
Use size!
Pick a random number q between 0 and n.
Start from the root. If left->size == q return current node value. If the left->size < q the go right else you go left. If you go right subtract q -= left->size + 1. Repeat until you output a node.
This give you o(height of tree). If the tree is balanced you get O(LogN).
If the tree is not balanced but you still want to keep O(logN) you can do the same thing but cap the maximum number of iterations. Note that in this case not all nodes have the same probability of being returned.
Yes, use size!
As Sorin said, pick a random number i between 0 and n - 1 (not n)
Then perform the following instruction:
Treenode rand_node = select(root, i);
Where select could be as follows:
TreeNode select_rec(TreeNode r, int i) noexcept
{
if (i == r.left.size)
return r;
if (i < r.left.size)
return select_rec(r.left, i);
return select_rec(r.right, i - r.left.size - 1);
}
Now a very important trick: the null node must be a sentinel node with size set to 0, what has sense because the empty tree has zero nodes. You can avoid the use of sentinel, but then the select() operation is lightly more complex.
If the trees is balanced, then select() is O(log n)

How would I recreate a binary tree from its inorder and postorder values?

Inorder: 3 2 1 5 4 6 8 9 7 11 10
Postorder: 1 2 3 4 5 6 9 11 10 7 8
I believe I am on the right track by taking the last postorder value as the root, finding that value in the Inorder list and splitting the tree to the left and the right of that value. From what I've been trying, I was able to come up with this result: It was not formatting correctly so I screenshot it.
Get the last element from the Postorder, this is your root element, then find that element in the Inorder and split the elements in left and right list giving you LEFT: "3 2 1 5 4 6" and RIGHT: "9 7 11 10" then walk the Postorder list and split it once you find the first number before the index of the root element in the Inorder list, in this case this is "6" so walk till 6 and this will give you "1 2 3 4 5 6" and the rest is "9 11 10 7". Then insert those lists in reverse order, e.g.: "6 5 4 3 2 1" and after that "7 10 11 9" this should give you the correct order of the tree.
It is a little tricky, maybe because contradicts a little the brain hemispheres ;-)
The parameters of interest are:
post: an array containing the postorder traversal
lp: left index of post array
rp: right index of post array
in: an array containing the inorder traversal
li: left index of in array
ri: riggh index of ìn array
The procedure is "naturally" recursive. At each recursion, the root always is post[rp]. That is the last visited node (in postorder).
So, the first thing to do is to know the index of the root in the array in. In order to compute that, we scan from li to ri and we search post[rp]. Let i the index of root in the array in. I assume that the tree does not have duplicated keys.
Given the index of root, then
i - li is the number of nodes in the left subtree
ri - i is the number of nodes in the right subtree
Now, in becomes naturally partitioned. The left subtree is between [li, i - 1] and the right subtree is between [i + 1, ri].
What I think is a little confuse is to determine where are the subtrees in post. The left subtree is between [lp, lp + (i - li) - 1] and the right is between [rp - (ri - i), rp - 1]. Take in account the numbers of nodes of each subtree expressed above (in the enumerated list).
With this knowledge we would be ready for designing an algorithm (I write in pseudo-C++, but I think it is very easy to translate to java):
Node * build_postorder(const vector<int> & post, long lp, long rp,
const vector<int> & in, long li, long ri)
{
if (lp > rp)
return nullptr; // we stop recursion when the tree is empty
Node * root = new Node(post[rp]); // Creates the root with key value post[rp]
int i = li;
for (; i <= ri; ++i) // search in inorder array the index of root
if (in[i] == post[rp])
break; // this line must always to execute it (if everything is oK)
LLINK(root) = build_postorder(post, lp, lp + (i - li) - 1, in, li, i - 1);
RLINK(root) = build_postorder(post, rp - (ri - i), rp - 1, in, i + 1, ri);
return root;
}
Good luck!

Genetic Operators on Binary Tree

I am having problems trying to wrap my head around applying genetic operators to binary trees.
Firstly I have methods that generate two types of trees for the initial population, namely Grow (tree of variable size) and Full (balanced same shape and size tree).
FULL GROW
(*) (*)
(+) (-) (5) (-)
(1)(2) (3)(4) (6) (7)
The class for each tree looks like this:
public class Tree<E>{
E element;
Tree<E> left, right;
double rawFit;
int hitRat;
public Tree(E element)
{
this.element=element;
}
public Tree (E element, Tree left, Tree right)
{
this.element = element;
this.left = left;
this.right = right;
}
//MORE
//CODE
}
Now this is where I am having troubles understanding how to implement genetic operators, namely Mutation and Crossover
Randomly selecting a tree from my initial population, how do I go about applying theses genetic operators?
For Mutation:
I need to randomly select a point in a parent tree.
Remove the entire subtree below that selected point.
Generate a new subtree of similar depth to the removed subtree.
Replace it back on the original parent tree and the selected point.
This is now the offspring.
Graphic Depiction:
PARENT
(*)
randomly chosen point --> (+) (-)
(1)(2) (3)(4)
OFFSPRING RANDOM SUBTREE
(*)
(NULL) (-) + (*)
(3) (4) (5) (6)
NEW OFFSPRING
(*)
(*) (-)
(5)(6) (3) (4)
I also need to do something similar for Crossover as well.
It seems easy in theory, but I have no idea how to code this (Java). Any help would be appreciated.
EDIT: The method I've used for generating a full tree looks like this:
private static final String[] OPERATORS = {"+", "-", "/", "*"};
private static final int MAX_OPERAND = 100;
public static Tree full(int depth) {
if (depth > 1) {
String operator = OPERATORS[random.nextInt(OPERATORS.length)];
return new Tree(operator, full(depth - 1), full(depth - 1));
} else {
return new Tree(random.nextInt(MAX_OPERAND) + 1);
}
}
I'll try and explain some of the steps in brief.
Randomly select a point in a parent tree
One way of doing this would be to choose a random number, say k, between 0 and the number of non-leaf elements in the tree. The random point would be the kth element while traversing the tree in order.
Replace the entire subtree below that selected point.
Simply set the subtree to the new generated tree. Something like this:
public class Tree<E> {
public void mutate() {
Tree tree = this.getRandomSubtree();
tree.replace(NEW_RANDOM_TREE);
}
public void replace(Tree<E> newTree) {
if(this.isLeftChild()) this.getParent().setLeft(newTree);
else this.getParent().setRight(newTree);
}
...
}
The getRandomSubtree() method returns a random point in the tree.
The getParent() method of a tree returns the immediate parent node.
Note that you'll also have to check some cases where the random sub-tree returned is the root itself.
Randomly select a point:
Select a Node at Random from Unbalanced Binary Tree
Remove subtree from selected node is not necessary, just get the depth of the selected subtree, and hold reference to it. http://www.geeksforgeeks.org/get-level-of-a-node-in-a-binary-tree/
Use your "full" method to generate a new random subtree with saved depth of old subtree and assign this subtree to your saved reference of old subtree, so the old subtree is killed by garbage collector.

Generating a Full Binary Tree Recursively through a Java Method

The method is supposed to take in two parameters one for depth and one for the integer value of the root of the tree. For Example: for any given N, returns the root reference of a full binary search tree of depth N such that the nodes store the integers 1, 2, …, 2 N+1 – 1. I'm struggling to get this right. Here is what I have:
public static BinaryNode BSTFactory(int top,int depth) {
BinaryNode root=new BinaryNode(null,null,top);
BinaryNode leftChild,rightChild;
if(depth==0){
return root;
}
if(depth==1){
//create 2 children left and right
leftChild=new BinaryNode(null,null,top-1);
rightChild=new BinaryNode(null,null,top+1);
root=new BinaryNode(rightChild,leftChild,top);
return root;
}
if(depth>1){
leftChild=BSTFactory(top-1,depth-1);
rightChild=BSTFactory(top+1,depth-1);
root=new BinaryNode(rightChild,leftChild,top);
return root;
}
return root;
}
First of all, the two parameters of your method depend on each other. For example, BSTFactory(1,3) can't be a full binary tree with a minimal node of 1, since if the root already contains the minimal node, the left sub-tree must be empty (unless you allow negative values in your tree, which is not clear from your question, since you seem to want the tree to store integers starting from 1).
Therefore, I would suggest a wrapper method that would accept only the depth, and calculate the matching root node. We'll see how the two parameters are related later.
Now let's look at some small full binary trees to figure out the recursion :
Depth 0
1
Depth 1
2
1 3
Depth 2
4
2 6
1 3 5 7
Depth 3
8
4 12
2 6 10 14
1 3 5 7 9 11 13 15
What can we learn from these examples?
If we are creating a full binary search tree of depth n :
The root would be 2^n
The left sub-tree will be rooted at root - 2^(n-1)
The right sub-tree will be rooted at root + 2^(n-1)
Therefore, the recusion should be :
public static BinaryNode BSTFactory(int root, int depth)
{
BinaryNode leftChild,rightChild;
if (depth==0){
return new BinaryNode(null,null,root);
} else {
leftChild=BSTFactory(root-Math.pow(2,depth-1),depth-1);
rightChild=BSTFactory(root+Math.pow(2,depth-1),depth-1);
return new BinaryNode(rightChild,leftChild,root);
}
}
Note that in order for this to work (i.e. that your minimal node would be 1), you must call the method with a root and depth such that root=2^depth. To ensure that, lets define a wrapper method :
public static BinaryNode BSTFactory(int depth)
{
return BSTFactory (Math.pow(2^depth),depth);
}
If you call the two parameter method with arbitrary root and depth, you can get binary trees such as :
BSTFactory (6,1)
6
5 7
BSTFactory (1,2)
1
-1 3
-2 0 2 4
There are still full binary trees, but their minimal value is not 1.

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.

Categories