Intersection of 2 binary search trees - java

Hey, So I want to create a new tree which is basically the intersection (mathematical definition of intersection) of 2 given binary search trees. I have a method that prints out all the nodes at a particular level of the tree and I have a method that can find out the depth of the tree.I am pasting my work so far though it is incomplete and I'm stuck with the logic.Help will be appreciated.
public static Bst<Customer> intersect (Bst<Customer> a, Bst<Customer> b){
Bst<Customer> result = new Bst<Customer>();
BTNode<Customer> cur1;
BTNode<Customer> cur2;
BTNode<Customer> cur3;
cur1=a.root;
cur2=b.root;
cur3=result.root;
int Resultdepth;
if(a.maxDepth()<b.maxDepth())
Resultdepth=a.maxDepth();
else
Resultdepth=b.maxDepth();
if(cur1==null || cur2==null){ // Handeling the root case intially
result = null;
}
else
cur3.item.set_account_id(cur1.item.get_accountid()+ cur2.item.get_accountid());
cur1=cur1.left;
cur2=cur2.left;
cur3=cur3.left;
while(<some check>){
}
return result;
}
public int maxDepth(){
return mD(root);
}
int mD(BTNode<E> node){
if (node==null) {
return(0);
}
else {
int lDepth = mD(node.left);
int rDepth = mD(node.right);
// use the larger + 1
return(Math.max(lDepth, rDepth) + 1);
}
}
// for printing the nodes at a particular level and giving the starting level
public void PrintAt(BTNode<E> cur, int level, int desiredLevel) {
if (cur == null) {
return;
}
if (level == desiredLevel) {
System.out.print(cur.item.toString() + "");
}
else {
PrintAt(cur.left, level+1, desiredLevel);
PrintAt(cur.right, level+1, desiredLevel);
}
}

You have to traversal both trees in order at the same time and "in sync".
I'd suggest to implement the Iterable interface for your class. Then you get the first values from both trees. If they are equal, put it in the new tree, and get the next values from both iterators. If not, iterate the iterator with the smaller values until the value you get is as least as big as the last value from the other iterator. Rinse and repeat.

The intersection of two trees is presumably the nodes that are in both trees?
Given that you'll have to explore the tree to do this, why not just do an in-order traversal, store the nodes and then do an intersection operation on ordered lists?

My suggestion for such an intersection is simple:
Given tree A and tree B, to find tree C = A \intersect B:
1: Copy either tree A or B. Let us assume A for clarity.
This copy is now your tree C. Now let's 'trim' it.
2: For c = C.root_node and b = B.root_node:
if b==c,
Repeat the procedure with nodes b.left, c.left
Repeat the procedure with nodes b.right, c.right
else,
Remove c (thereby removing all subsequent children, it is implied they are unequal)
If this implementation would work, it would avoid the use of iterators and the like, and boil down to a simple recursive traversal.
(Like this!)
Ask if you would like further clarification.
Regards.

For the recursive implementation of finding intersection of two binary search trees , I came up with the following code. I am not very sure of the time complexity, but it does work all right.
void BST::findIntersection(cell *root1, cell * root2) {
if(root1 == NULL ) {
// cout<<"Tree 1 node is null , returning"<<endl;
return;
}
if(root2 == NULL) {
// cout<<"Tree 2 node is null , returning"<<endl;
return;
}
//cout<<"Comparing tree 1 : "<<root1->data<< " and tree 2 : " << root2->data<<endl;
if(root1->data==root2->data) {
// cout<<"tree 1 equal to tree 2 "<<endl;
insert(root1->data);
// cout<<"Inserting in new tree : "<<root1->data<<endl;
findIntersection(root1->left,root2->left);
findIntersection(root1->right, root2->right);
}
else if(root1->data>root2->data) {
// cout<<"tree 1 > tree 2 "<<endl;
findIntersection(root1,root2->right);
findIntersection(root1->left, root2);
}
else {
// cout<<"tree 1 < tree 2 "<<endl;
findIntersection(root1->right,root2);
findIntersection(root1, root2->left);
}
}

Related

Computing the size of a linked list using recursion/helper function - Java

Beginner here using Java (first year student), and am unable to get the below function to work. The goal is to use recursion and a helper function to compute the size of a singly linked list. When running the code against test lists, it keeps returning List changed to [].
I'm struggling in general with Java, so any help is appreciated. Thank you
public class MyLinked {
static class Node {
public Node(double item, Node next) {
this.item = item;
this.next = next;
}
public double item;
public Node next;
}
int N;
Node first;
public int sizeForward() {
return sizeForwardHelper(first);
}
public int sizeForwardHelper(Node n) {
Node current = first;
if (current == null) {
return 0;
} else {
first = first.next;
return sizeForward() + 1;
}
}
I believe I have the first portion set up to return 0 if there are no elements in the List. I believe it's the second part that isn't setting up correctly?
Thanks
Because it’s important for your learning to not spoonfeed you, I’ll describe an approach rather than provide code.
Use this fact:
The length of the list from any given node to the end is 1 plus the length measured from the next node (if there is one).
Usually (as would work here), recursive functions take this form:
If the terminating condition is true, return some value
Otherwise, return some value plus the recursively calculated value
When writing a recursive function, first decide on the terminating condition. In this case, n == null is the obvious choice, and you’d return 0, because you’ve run off the end of the list and the length of nothing (ie no node) is nothing. This also handles the empty list (when first is null) without any special code.
Otherwise, return 1 (the length of one node) plus the length of next.
Put that all together and you’ll have your answer.
——
Hint: The body of the recursive helper method can be coded using one short line if you use a ternary expression.
Instead of calling your wrapper function call your helper function recursively. Try the following:
public int sizeForward () {
return sizeForwardHelper (first);
}
public int sizeForwardHelper(Node n) {
if (n == null) // base case
return 0;
return sizeForwardHelper(n.next) + 1; // count this node + rest of list
}
Your method that computes the size of the list actually modifies the list in the process (with first = first.next; you set the first element to the next, and since there is a recursion, the first element always end up being null which is equivalent to an empty list with your design). Your method will work once, but your list will be empty afterwards.
To illustrate this, I added a print next to the instruction first = first.next; and wrote the following main:
public static void main(String[] args) {
Node n2 = new Node(2d, null);
Node n1 = new Node(1d, n2);
Node n = new Node(0, n1);
MyLinked l = new MyLinked(n);
System.out.println("The first element is: "+l.first.item);
System.out.println("The size is: "+l.sizeForward());
System.out.println("The first element is: "+l.first);
}
It yields:
The first element is: 0.0
first is set to 1.0
first is set to 2.0
first is set to null
The size is: 3
The first element is: null
Clearly, you should not modify the list while computing its size. The helper method should return 0 if the node is null (empty list), and 1 plus the size of the rest of the list otherwise. Here is the code.
public int sizeForwardHelper(Node n) {
if (n == null)
return 0;
else
return sizeForwardHelper(n.next) +1;
}
The goal of the arg free method sizeForward() is just to call the helper. The helper should not use it though.

Verify that all nodes at given level have different values in binary tree

My question is, can this problem be solved without using any data structures (stack, list, etc) or it requires one? (I would also like to see the solution in both cases, if possible).
The problem:
Having a BinaryTree class that represents binary trees that contains integer values. Assume that there are already implemented methods:
public BinaryTree right(); // returns right children
public BinaryTree left(); // returns left children
public int val(); // returns value of root node.
Implement the following recursive method :
public static boolean allDifferentAtLevel(BinaryTree a, int lev){...}
that receives a Binary Tree of integers and returns true only if all the values of the nodes of a at level lev all have different values.
Thanks in advance for your time.
We can use HashSet<Integer> to keep track of the data present at levth level.
public static boolean allDifferentAtLevel(BinaryTree a, int lev){
return checker(new HashSet<Integer>(),a,0,lev); //EmptySet, Root, CurrentLevel, Level
}
public static boolean checker(HashSet<Integer> set,BinaryTree a, int currentLevel, int lev) {
if(a==null) //If current node of tree is null, return true.
return true;
if(currentLevel==lev) //If currentLevel is the required level, We don't need to move further.
//We can just validate the data at currentLevel and return the appropriate value.
{
int value=a.val();
if(set.contains(value)) //If set contains the value, Duplication found.
return false;
set.add(value);
return true;
}
//Check for both of the children.
return checker(set,a.left(),currentLevel+1,lev) && checker(set,a.right(),currentLevel+1,lev);
}
It's possible however it would be inefficient - you can implement two recursive functions:
Doing DFS reach all the nodes at required level
From the first function (for each node at required level) call another function that'll count (also using DFS) all the nodes with values equal to the value of the node considered by the first function and check that this count is equal to 1.
Yes, this is solveable with recursion without additional data structures.
Let's try to define what the allDifferentAtLevel(BinaryTree tree, int lev) method should look like for different levs:
For lev=0 the result is simply false since all nodes on the level 0 have the same values. There's just one node on level 0 so all nodes have the same value.
For lev=1 it is quite trivial to check tree.right().val() == tree.left().val() (add null checks).
For higher levels (lev>1) you should call the method recursively. Basically, allDifferentAtLevel(tree.left(), lev - 1) and allDifferentAtLevel(tree.right(), lev - 1) would make sure that left subtree and right subtree satisfy the condition. Unfortunately this is insufficient since left and right subtrees may have some common value between them.
But it is possible to work around this checking not just left and right but all combinations of subtrees two levels deeper. Something like:
BinaryTree ll = tree.left() == null ? null : tree.left().left();
BinaryTree lr = tree.left() == null ? null : tree.left().right();
BinaryTree rl = tree.right() == null ? null : tree.right().left();
BinaryTree rr = tree.right() == null ? null : tree.right().right();
BinaryTree ll_lr = tree.left();
BinaryTree ll_rl = new BinaryTree(0, ll, rl);
BinaryTree ll_rr = new BinaryTree(0, ll, rr);
BinaryTree lr_rl = new BinaryTree(0, lr, rl);
BinaryTree lr_rr = new BinaryTree(0, lr, rr);
BinaryTree rl_rr = tree.right();
return allDifferentAtLevel(ll_lr, lev - 1) &&
allDifferentAtLevel(ll_rl, lev - 1) &&
allDifferentAtLevel(ll_rr, lev - 1) &&
allDifferentAtLevel(lr_rl, lev - 1) &&
allDifferentAtLevel(lr_rr, lev - 1) &&
allDifferentAtLevel(rl_rr, lev - 1);
There are four subtrees two levels deeper (ll, lr, rl, rr). But we can't just check these subtrees, we have to check them against each other. There are six possible distinct pairs of these subtrees. In order to check these subtrees against each other, we can create one binary tree for each of the distinct pairs (ll_lr, ll_rl, ll_rr, lr_rl, lr_rr, rl_rr) and then check each of these binary trees recursively. If any of the subtrees ll, lr, rl, rr have equal elements on the lev-2, there will be a pair of them having equal element on the lev-1.
So yes, the problem is solveable with recursion without additional data structures. I don't consider BinaryTree an additional data structure here.
Having said this, using an additional data structure like a set would make the task easier.

How to implement in-order, pre-order and post-order traversals of a binary tree with data from 3 arrays

I understand that the binary tree can be implemented easily this way:
class Node {
int key;
Node left, right;
public Node(int item) {
key = item;
left = right = null;
}
}
class BinaryTree {
Node root;
public BinaryTree() {
root = null;
}
}
Also the methods for traversal that I've figured out are:
void printInorder(Node node) {
if (node == null) return;
printInorder(node.left);
System.out.print(node.key + " ");
printInorder(node.right);
}
void printPreorder(Node node) {
if (node == null) return;
System.out.print(node.key + " ");
printPreorder(node.left);
printPreorder(node.right);
}
void printPostorder(Node node) {
if (node == null) return;
printPostorder(node.left);
printPostorder(node.right);
System.out.print(node.key + " ");
}
However, I'm given this starter file where the tree data is in 3 arrays: key[],left[] and right[], so key[] elements are the data of the nodes, left and right elements are the indexes of the left and right child of the ith node, so Node root is keys[0], with left child keys[left[0]] and keys[right[0].
I'm not sure how (or if I need) to convert the 3 arrays into a Binary tree using the Node and BinaryTree classes. Where should the Node and BinaryTree classes should go? Outside of tree_orders? Inside of tree_orders but outside of TreeOrders? (sorry about the "creative" naming convention, not mine)
Do I need to iterate over the three arrays to build the tree nodes?
I tried implementing the insert(int data) and insert(Node n, int data) methods below to convert the arrays into nodes but it doesn't seem to fill the tree.
Node insert(int data) {
root = insert(root, data);
return node;
}
Node insert(Node node, int data) {
if (node == null) {
node = new Node(data)
}
else {
if (node.left == null) insert(node.left, data);
else insert(node.right, data);
}
return node;
}
It's just 5 months that I've started learning programming (picked Java) and I've worked with Trees before but this starter is an OOP puzzle for me, I'll need to recheck my OOP knowledge.
This is an example of how the input and output should show (-1 = null node / 5 = number of given nodes):
Input:
5
4 1 2
2 3 4
5 -1 -1
1 -1 -1
3 -1 -1
Output:
1 2 3 4 5
4 2 1 3 5
1 3 2 5 4
Your question is not very clear. The title asks about traversal but you also have worries about reading 100.000 nodes and about giving nodes a name, and about iteration/recursion slowness. That's a whole muddled bundle of confusion!
The traversal logic you show looks OK at first glance.
Assuming you want to build a binary tree using your Node class from the three arrays you could do this (you don't need the BinaryTree class, it only contains the root Node):
class TreeMaker {
private int[] keys, left, right;
TreeMaker(int[] keys, int[] left, int[] right) {
this.keys = keys;
this.left = left;
this.right = right;
}
public Node make() {
return makeNode(0);
}
private Node makeNode(int index) {
if (index < 0 || index >= keys.length) {
return null;
}
Node node = new Node(keys[index]);
node.left = makeNode(left[index]);
node.right = makeNode(right[index]);
return node;
}
}
I think 100.000 nodes is not that much. Making it should not pose a problem either memory wise or speed wise (unless you start doing complex searching, indexing or other fun stuff). NOTE: after seeing the artificial limitations imposed on the Thread running this code, it might be a problem.
You don't have to store nodes in named variables or otherwise name them. Just making sure the binary tree nodes refer to the correct children is enough.
EDIT: about your starter file
This is total crap:
while (!tok.hasMoreElements())
tok = new StringTokenizer(in.readLine());
Firstly StringTokenizer is a legacy class that should no longer be used (for new code). String.split() is the alternative to use nowadays. Furthermore, creating a new instance of StringTokenizer for each line is unnecessary and wasteful. Are you bound to use this code as-is?
And do I understand that you're supposed to enter your tree data from the command line? Why not read the data from a file so you only have to type it in once?
And how are you supposed to type in a valid binary tree? The values in left[] and right[] are actually indices of the key[], so you will have to figure out, whilst typing, in which index each child node will be stored? Crazy stuff. The person setting you this task much be a little bit sadistic. There are much better ways to store binary trees in a single array, see for example this lecture.
This is also remarkable:
static public void main(String[] args) throws IOException {
new Thread(null, new Runnable() {
public void run() {
try {
new tree_orders().run();
} catch (IOException e) {
}
}
}, "1", 1 << 26).start();
}
Here the class tree_orders (sic.) is run in a Thread with a stack size of 1 << 23. This stack size is a hint to the Java runtime to limit the memory needed to keep track of nested method calls to 8388608 bytes. This is probably intended to either make you hit a limit when implementing this recursively, or to ensure that you don't (I haven't figured out which one it is).
In order to apply my TreeMaker in this example, you could use in the run() method:
public void run() throws IOException {
TreeOrders tree = new TreeOrders();
tree.read();
TreeMaker treeMaker = new TreeMaker(tree.keys, tree.left, tree.right);
Node root = treeMaker.make();
printInorder(root);
printPreorder(root);
printPostorder(root);
}
But I get the impression you are supposed to just implement the three given methods and do the traversal on the existing data structure (3 arrays).
What a poor design, those arrays. Anyway, if you want or need to stick to it, traversing the tree is not too bad:
void printInorder(int index) {
if (index == -1) return;
printInorder(left[index]);
System.out.print(keys[index] + " ");
printInorder(right[index]);
}
Similarly for the other traversal orders. I am assuming -1 in either left or right means no decendant. To print the whole tree, call printInOrder(0) since the root is in index 0.
Edit: I believe your example gives the following arrays:
int[] keys = { 4, 2, 5, 1, 3 };
// indices 0..4
int[] left = { 1, 3, -1, -1, -1 };
int[] right = { 2, 4, -1, -1, -1 };
With these, calling printInorder(0) and then System.out.println() prints:
1 2 3 4 5

Change the value of the leaves of a tree with the sum of the path from root to leaf

I have to create a function that took a tree t not empty, change the content of each leaf in its field by putting the sum of the values contained in the nodes of the path from the root to the leaf (including root and leaf).
So I created this:
void sum(BinTree t) {
while(!t.isLeaf()) {
sumL += sum(t.left);
sumR += sum(t.right);
}
t.element = ?;
}
boolean isLeaf(BinTree t) {
return t.left == null && t.right == null;
}
What should I put in place of "?"? I don't think that the function is correct..
I'm unable to create recursive functions for the binary trees, I find them very complicated..
Thanks
EDIT: I changhed my method:
void leafSum(BinTree t) {
sumLeaf(root, 0);
}
void leafSum(BinTree t, int tot) {
if(t->left == NULL && t->right == NULL)
t->elem = tot;
else {
sumLeaf(t->left, tot + t->elem);
sumLeaf(t->right, tot + t->elem);
}
}
Rather than providing a solution I'll give a few hints to help you along. Ask questions if any of it isn't clear.
The basic algorithm you are looking for is: for each node if it's a leaf then store the sum, if it's not a leaf then repeat for both child nodes.
While recursion isn't essential it will make the solution simpler in this case. It's not complex: the basic rule is to always have a termination condition (in your case, that you are looking at a leaf) before recursing.
You should pass a running total to the function so that you don't need to look back up the tree once you get to a leaf. That's not complex: just add the current value for the node to the running total before storing it (for leaves) or passing it to child node (for non-leaves).
Start with a running total of zero when you call the function for the root node.
That's about it - you should be able to come up with a solution from those hints.

Balancing a BST with weights

I'm building a recursive Java method to balance a binary search tree (using ints, but designed generic) using weights in each node. For my purpose, the weight of a node is defined as the number of children + 1.
2
/ \
1 3
The weight of the root is 3, and the weight of both leaves is 1.
At the end of the balancing, the value at any node should be the median of the values at all nodes in the subtree rooted at that node.
Here is my code:
public void weightBalance (BinarySearchTree<AnyType> t) {
// Base case
if (t.getRoot().left == null && t.getRoot().right == null) {
return;
}
// Get median of tree
AnyType median = t.getMedian();
// Create new BST with median as root
BinarySearchTree<AnyType> newTree = new BinarySearchTree<AnyType>();
newTree.insert(median);
// Insert all values except median into new BST
ArrayList<AnyType> stack = new ArrayList<AnyType>();
inorderTraverse(t.getRoot(), stack);
Iterator<AnyType> itr = stack.iterator();
while (itr.hasNext()) {
AnyType temp = itr.next();
if (temp != median) { // Comparing values or reference?
newTree.insert(temp);
}
}
// Replace old BST with new BST
t = newTree; // t is a copy of the reference, is this the problem?
// Recurse through children
// Tree constructor for reference:
// public BinarySearchTree (BinaryNode<AnyType> t) {
// root = t;
// }
if (t.getRoot().left != null) {
weightBalance(new BinarySearchTree(t.getRoot().left));
}
if (t.getRoot().right != null) {
weightBalance(new BinarySearchTree(t.getRoot().right));
}
}
I'm trying to modify the tree in place without returning anything, but the code does not change the tree. I know I'm messing by passing by reference and passing by value somewhere, but I can't figure out where - can anyone help out? I've spent a few hours debugging but I get really confused when debugging recursion.
Balancing algorithms are fairly common and well documented, e.g. TreeMap is a BST and you can see it source. I have never seen it use a copy of data, I doubt you need to create a stack or build a new tree just to balance it.
The normal behaviour is to rotate nodes, left or right, or a more complex combination of both. This reduces the work involved and doesn't create an garbage.

Categories