I'm trying to make a method to collect all the nodes from a given tree passed as a parameter, but it seems that it isn't reading the left branch of any node.
The code I've developed so far is the following one.
private ArrayList<T> collect(AVLTree<T> tree, AVLNode<T> tRoot, ArrayList<T> l) {
ArrayList<T> nodes = l;
if (tRoot == null)
return null;
else {
if (!nodes.contains(tRoot.element())) {
nodes.add(tRoot.element());
if (tRoot.getRight() != null) {
collect(tree, tRoot.getRight(), nodes);
return nodes;
}
else if (tRoot.getLeft() != null) {
collect(tree, tRoot.getLeft(), nodes);
return nodes;
}
}
}
return nodes;
}
Hope you can help me out a little bit with this as I'm really stuck with it right now...
Two things that are making the code not work.
You only check one branch of any node, meaning if right branch is being checked, the left one will not even if there are nodes in the left
You're returning too early. You don't need to return right after you check each branch. By doing so, you're skipping the left branches again if right branch exists.
The following fixes will work.
private ArrayList<T> collect(AVLTree<T> tree, AVLNode<T> tRoot, ArrayList<T> l) {
ArrayList<T> nodes = l;
if (tRoot == null)
return null;
else {
if (!nodes.contains(tRoot.element())) {
nodes.add(tRoot.element());
if (tRoot.getRight() != null) {
collect(tree, tRoot.getRight(), nodes);
}
if (tRoot.getLeft() != null) {
collect(tree, tRoot.getLeft(), nodes);
}
}
}
return nodes;
}
EDIT: After staring at the code a bit more. There are few places where code redundancy exists. They can be simplified and cleaned up to the following:
private ArrayList<T> collect(AVLTree<T> tree, AVLNode<T> tRoot, ArrayList<T> l) {
ArrayList<T> nodes = l;
if (tRoot == null)
return null;
if (!nodes.contains(tRoot.element())) {
nodes.add(tRoot.element());
collect(tree, tRoot.getRight(), nodes); // this is safe since null check exists at top
collect(tree, tRoot.getLeft(), nodes);
}
return nodes;
}
Related
I'm struggling to find a proper way to get a speedup from this stream:
StreamSupport.stream(new BinaryTreeSpliterator(root), true)
.parallel()
.map(node -> processor.onerousFunction(node.getValue()))
.mapToInt(i -> i.intValue())
.sum()
onerousFunction() is just a function that makes the thread work for a bit and returns the int value of the node.
No matter how many cpus i use, the execution time always remains the same.
I think the problem stands in the Spliterator i wrote:
public class BinaryTreeSpliterator extends AbstractSpliterator<Node> {
private LinkedBlockingQueue<Node> nodes = new LinkedBlockingQueue<>();
public BinaryTreeSpliterator(Node root) {
super(Long.MAX_VALUE, NONNULL | IMMUTABLE);
this.nodes.add(root);
}
#Override
public boolean tryAdvance(Consumer<? super Node> action) {
Node current = this.nodes.poll();
if(current != null) {
action.accept(current);
if(current.getLeft() != null)
this.nodes.offer(current.getLeft());
if(current.getRight() != null)
this.nodes.offer(current.getRight());
return true;
}
return false;
}
}
But i really can't find a good solution.
To process data in parallel, you need a trySplit implementation to return partial data as a new Spliterator instance. The spliterator instances are traversed by a single thread each. So you don’t need a thread safe collection within your spliterator, by the way. But your problem is that you are inheriting the trySplit implementation from AbstractSpliterator which does attempt to provide some parallel support despite not knowing anything about your data.
It does so, by requesting some items sequentially, buffering them into an array and returning a new array based spliterator. Unfortunately, it does not handle “unknown size” very well (the same applies to the parallel stream implementation in general). It will buffer 1024 elements by default, buffering even more the next time, if there are as much elements. Even worse, the stream implementation will not use the array based spliterator’s good splitting capabilities, because it treats “unknown size” like the literal Long.MAX_VALUE, concluding that your spliterator has much more elements than the 1024 elements in the array, hence, will not even try to split the array based spliterator.
Your spliterator can implement a much more suitable trySplit method:
public class BinaryTreeSpliterator extends AbstractSpliterator<Node> {
/**
* a node that has not been traversed, but its children are only
* traversed if contained in this.pending
* (otherwise a different spliterator might be responsible)
*/
private Node pendingNode;
/** pending nodes needing full traversal */
private ArrayDeque<Node> pending = new ArrayDeque<>();
public BinaryTreeSpliterator(Node root) {
super(Long.MAX_VALUE, NONNULL | IMMUTABLE);
push(root);
}
private BinaryTreeSpliterator(Node pending, Node next) {
super(Long.MAX_VALUE, NONNULL | IMMUTABLE);
pendingNode = pending;
if(next!=null) this.pending.offer(next);
}
private void push(Node n) {
if(pendingNode == null) {
pendingNode = n;
if(n != null) {
if(n.getRight()!=null) pending.offerFirst(n.getRight());
if(n.getLeft() !=null) pending.offerFirst(n.getLeft());
}
}
else pending.offerFirst(n);
}
#Override
public boolean tryAdvance(Consumer<? super Node> action) {
Node current = pendingNode;
if(current == null) {
current = pending.poll();
if(current == null) return false;
push(current.getRight());
push(current.getLeft());
}
else pendingNode = null;
action.accept(current);
return true;
}
#Override
public void forEachRemaining(Consumer<? super Node> action) {
Node current = pendingNode;
if(current != null) {
pendingNode = null;
action.accept(current);
}
for(;;) {
current = pending.poll();
if(current == null) break;
traverseLocal(action, current);
}
}
private void traverseLocal(Consumer<? super Node> action, Node current) {
do {
action.accept(current);
Node child = current.getLeft();
if(child!=null) traverseLocal(action, child);
current = current.getRight();
} while(current != null);
}
#Override
public Spliterator<Node> trySplit() {
Node next = pending.poll();
if(next == null) return null;
if(pending.isEmpty()) {
pending.offer(next);
next = null;
}
if(pendingNode==null) return next==null? null: new BinaryTreeSpliterator(next);
Spliterator<Node> s = new BinaryTreeSpliterator(pendingNode, next);
pendingNode = null;
return s;
}
}
Note that this spliterator would also qualify as ORDERED spliterator, maintaining a top-left-right order. An entirely unordered spliterator could be implemented slightly simpler.
You may implement a more efficient forEachRemaining method than the inherited default, e.g.
#Override
public void forEachRemaining(Consumer<? super Node> action) {
Node current = pendingNode;
if(current != null) {
pendingNode = null;
action.accept(current);
}
for(;;) {
current = pending.poll();
if(current == null) break;
traverseLocal(action, current);
}
}
private void traverseLocal(Consumer<? super Node> action, Node current) {
do {
action.accept(current);
Node child = current.getLeft();
if(child!=null) traverseLocal(action, child);
current = current.getRight();
} while(current != null);
}
but this method might cause stackoverflow errors, if your application has to deal with unbalanced trees (specifically, very long left paths in this example).
I implemented the Set ADT using the standard approach with nodes (TreeNodes) using a binary search tree.
I have the task of implementing it using the same old nodes except that they have an additional boolean field "active", which can "switch on" (setActive(true)) or "switch off" (setActive(false)) the nodes when removing. This keeps removed nodes there, but they are ignored when we implement toString(), which returns the items in the set.
I was able to implement all the methods of the Set ADT apart from removeAny() (that removes anything from the set, essentially "switches it off"). The problem is that I have to find any node that is "switched on". For this, I have to go through each node and check if one is active. I tried to write the code using recursive calls, but got confused about what to return. Here is my attempt (in Java):
public T removeAny() throws Exception {
if (size == 0) {
throw new Exception ("You cannot remove anything since the set is empty!");
}
return removeAnyHelper (root);
}
public T removeAnyHelper (OnOffTreeNode <T> node) {
if (node == null) {
return root.getValue();
}
if (node.getActive() == true) {
size--;
node.setActive(false);
return node.getValue();
}
removeAnyHelper (node.getLeft());
return removeAnyHelper (node.getRight());
}
How can I fix this method? What should I return?
I tried some if-statements to return both removeAnyHelper (node.getLeft()) and removeAnyHelper (node.getRight()), but this didn't work.
If the node is null, you presumably need to return null (since nothing was removed).
If the recursive call on the left child doesn't return null, it means we removed a node and we need to return it. Otherwise we need to return the result of the call on the right child.
Turning that into code:
public T removeAnyHelper (OnOffTreeNode <T> node) {
if (node == null) {
return null;
}
if (node.getActive()) { // == true is unnecessary
size--;
node.setActive(false);
return node.getValue();
}
T removedNode = removeAnyHelper (node.getLeft());
if (removedNode != null)
return removedNode;
else
return removeAnyHelper (node.getRight());
}
Although I wouldn't really recommend using active/inactive flags for nodes in a BST - deleting a node isn't particularly hard to implement and avoids the problem of having a large number of inactive nodes.
More generally speaking, there are also self-balancing BST's, which avoid reduced efficiency due to unbalanced trees.
Well I don't think removeAny is a proper method for a Set, but anyway.
You can (and probably should) removeAny by removing the first leaf:
private T removeAnyHelper(OnOffTreeNode <T> node) {
if (!present(node.getLeft() && !present(node.getRight())) {
// no children -> this is a leaf, return
node.setActive(false);
return node.getValue();
}
// return left first, or right if left not present
if (present(getLeft())) {
return removeAnyHelper(getLeft());
}
return removeAnyHelper(getRight());
}
private boolean present(OnOffTreeNode<T> node) {
return node != null || node.isActive();
}
Note that you also have a mistake in your base removeAny method because it doesn't check for root's active state:
public T removeAny() throws NoSuchElementException {
if (size == 0 || !root.isActive()) {
throw new NoSuchElementException ("cant remove");
}
return removeAnyHelper(root);
}
My tree nodes have the 3 string fields and 3 node fields which are left, middle and right.
One of the problems is that the method can only take string as a parameter
This is what I have
public TreeNode findNode(String name) {
TreeNode pointer = this.getRoot();
if (pointer.getName().equals(name))
return pointer;
if (pointer.getLeft() != null)
pointer = pointer.getLeft();
findNode(name);
if (pointer.getMiddle() != null)
pointer = pointer.getMiddle();
findNode(name);
if (pointer.getRight() != null)
pointer = pointer.getRight();
findNode(name);
return null;
}
This causes a stack overflow error because I just keep setting the pointer to root. But I have to start somewhere and my only parameters for the method can be name. I can't seem to see how to do this.
You can use a list as a parameter stack.
public TreeNode findNode(String name) {
List<TreeNode> stack = new ArrayList<TreeNode>();
stack.add(this.getRoot());
while (!stack.isEmpty())
{
TreeNode node = stack.remove(0);
if (node.getName().equals(name))
return node;
if (pointer.getLeft() != null)
stack.add(node.getLeft());
if (node.getMiddle() != null)
stack.add(node.getMiddle());
if (node.getRight() != null)
stack.add(node.getRight());
}
return null;
}
You can remove from the end of the list instead of the front of the list if you want to search depth-first.
Im guessing you cannot change the signature of this function. Have a helper function that takes in two parameters, (Node and name) that you call with root and name.
In all three cases (left, middle, right), you are calling findNode(name) but not for those objects, instead it is for this. That's why you get stack overflow.
Use an auxiliary method that takes in a TreeNode parameter in addition to the string:
public TreeNode findNode(String name) {
return auxFindNode(this.getRoot(), name);
}
private TreeNode auxFindNode(TreeNode node, String name) {
//perform your recursive traversal here
}
Your code as it stands will never work because you keep setting pointer to the root of the tree at the beginning of the method. So all your recursive calls start with the root of the tree.
If you prefer not to use another method, you can traverse the tree iteratively by using stack:
public TreeNode findNode(String name) {
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode foundNode = null;
while(!stack.empty() && foundNode == null) {
TreeNode node = stack.pop();
if(node.getName().equals(name)) {
foundNode = node;
} else {
if(node.getLeft() != null) {
stack.push(node.getLeft();
}
if(node.getMiddle() != null) {
stack.push(node.getMiddle());
}
if(node.getRight() != null) {
stack.push(node.getRight());
}
}
}
return foundNode;
}
I made a binary search tree in Java but I'm having troubles whit the deleting nodes part. I managed to erase the node when it has only 1 son, and I have the idea to make the deletion when it has 2 sons, anyways the method I'm using when it has no sons (when it's a leaf) is not working in Java. Normally in C++ I would assign the Node "null" but it doesn't work here.
if (numberOfSons(node) == 0) {
node= null;
return true;
}
That's the portion of the code that takes care of the nulling part. When I debug it, it is referencing the correct node and it's assigning it the null value, but when I return to the Frame where I'm calling the delete method for my tree the node is still there. What's the correct way to "null" an object in Java? I thought everything was a pointer in here and therefore this would work, but I think it doesn't.
When you're nulling something you just make the reference in the scope you're in null. It doesn't affect anything outside.
Let me explain by example. Say you have a method foo:
public void foo(Node node) {
node = null;
if(node == null) {
System.out.println("node is null");
} else {
System.out.println("node is not null");
}
}
Now you call it like this:
public void doSomething() {
Node node = new Node();
foo(node);
if(node == null) {
System.out.println("Original node is null");
} else {
System.out.println("Original node is not null");
}
}
In your console you'll get:
node is null
original node in not null
The reason is that it's not a pointer, it's a reference. When you're nulling a reference, you just say "make this reference synonym to null". It doesn't mean that the object is deleted, it may still exist in other places. There is no way to delete objects in java. All you can do is make sure no other object points to them, and the garbage collector will delete the objects (sometime).
Nothing remains but to reinsert either left or right subtree. For instance:
class BinaryTree<T extends Comparable<T>> {
class Node {
Node left;
Node right;
T value;
}
Node root;
void delete(T soughtValue) {
root = deleteRec(root, soughtValue);
}
Node deleteRec(Node node, T soughtValue) {
if (node == null) {
return null;
}
int comparison = soughtValue.compareTo(node.value);
if (comparison < 0) {
node.left = deleteRec(node.left, soughtValue);
} else if (comparison > 0) {
node.right = deleteRec(node.right, soughtValue);
} else {
if (node.left == null) {
return node.right;
} else if (node.right == null) {
return node.left;
} else {
// Two subtrees remain, do for instance:
// Return left, with its greatest element getting
// the right subtree.
Node leftsRightmost = node.left;
while (leftsRightmost.right != null) {
leftsRightmost = leftsRightmost.right;
}
leftsRightmost.right = node.right;
return node.left;
}
}
return node;
}
}
As Java does not have aliases parameters as in C++ Node*& - a kind of in-out parameter, I use the result of deleteRec here. In java any function argument that is an object variable will never change the variable with another object instance. That was one of the language design decisions like single inheritance.
I'm trying to implement an Iterator in my own TreeSet class.
However my attempt at creating it only works until the current node is the root.
The Iterator looks like this:
Constructor:
public TreeWordSetIterator()
{
next = root;
if(next == null)
return;
while(next.left != null)
next = next.left;
}
hasNext:
public boolean hasNext()
{
return next != null;
}
Next:
public TreeNode next()
{
if(!hasNext()) throw new NoSuchElementException();
TreeNode current = next;
next = findNext(next); // find next node
return current;
}
findNext:
private TreeNode findNext(TreeNode node)
{
if(node.right != null)
{
node = node.right;
while(node.left != null)
node = node.left;
return node;
}
else
{
if(node.parent == null)
return null;
while(node.parent != null && node.parent.left != node)
node = node.parent;
return node;
}
}
This works fine up until I get to my root node. So I can only iterate through the left child of root, not the right. Can anyone give me a few tips on what I'm doing wrong? I don't expect a solution, just a few tips.
Question: How can I find the next node in a TreeSet given each node points to its parent, left-child and right-child.
Thanks in advance
It helps to consider the rules of a Binary Search Tree. Let's suppose the previously returned node is n:
If n has a right subtree, then the node with the next value will be the leftmost node of the right subtree.
If n does not have a right subtree, then the node with the next value will be the first ancestor of n that contains n in its left subtree.
Your code is correctly handling the first case, but not the second. Consider the case where node is the leftmost leaf of the tree (the starting case). node has no right child, so we go straight to the else. node has a parent, so the if-clause is skipped. node.parent.left == node, so the while clause is skipped without executing at all. The end result is that node gets returned. I'd expect your iterator to continue returning the same node forever.
There are 3 main ways you can iterate a binarry tree
private void inOrder(TreeNode node) {
if(isEmpty())return;
if(node.getLeftNode()!=null)inOrder(node.getLeftNode());
System.out.print(node.getNodeData()+" ");
if(node.getRightNode()!=null)inOrder(node.getRightNode());
}
private void preOrder(TreeNode node) {
if(isEmpty())return;
System.out.print(node.getNodeData()+" ");
if(node.getLeftNode()!=null)preOrder(node.getLeftNode());
if(node.getRightNode()!=null)preOrder(node.getRightNode());
}
private void postOrder(TreeNode node) {
if(isEmpty())return;
if(node.getLeftNode()!=null)postOrder(node.getLeftNode());
if(node.getRightNode()!=null)postOrder(node.getRightNode());
System.out.print(node.getNodeData()+" ");
}
//use
inOrder(root);
preOrder(root);
postOrder(root);
Its simple as that ,your code doesn't really makes sense to me, is there something else you are trying to do besides iterating in one of this ways?
I think you need to save previous point in your iterator so you know where you've been before
Here some code but be aware that it is not complete you should do it by yourself and it's just to show you the idea. it also doesn't handle the root node.
findNext(TreeNode node, TreeNode previousNode) {
if(node.left != null && node.left != previousNode && node.right != previousNode){ //go left if not been there yet
return node.left;
}
if(node.right != null && node.right != previousNode){ //go right if not been there yet
return node.right;
}
return findNext(node.parent, node); //go up and pass current node to avoid going down
}
A good approach is to use a stack to manage sequencing, which is sort of done for you if you use a recursive traversal (instead of trying to build an Iterator at all) as described in SteveL's answer.
As you want to start from the left, you first load onto the stack the root node and its leftmost children in the proper order (push while going down to the left from the root).
Always pop the next from the top of the stack, and push its right child (if any) and all its leftmost children before returning the one you just popped, so that they're next in line.
By this approach, the top of the stack will always be the next to return, and when the stack is empty, there's no more...
In code:
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Stack;
public class TreeNodeInOrderIterator<T> implements Iterator<T> {
private final Stack<TreeNode<T>> stack;
public TreeNodeInOrderIterator(TreeNode<T> root) {
this.stack = new Stack<TreeNode<T>>();
pushLeftChildren(root);
}
#Override
public boolean hasNext() {
return !stack.isEmpty();
}
#Override
public T next() {
if (!hasNext())
throw new NoSuchElementException();
TreeNode<T> top = stack.pop();
pushLeftChildren(top.right);
return top.val;
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
private void pushLeftChildren(TreeNode<T> cur) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
}
}
In this code, TreeNode is defined by
public class TreeNode<T> {
T val;
TreeNode<T> left;
TreeNode<T> right;
TreeNode(T x) { val = x; }
}
If you want to have each node also know its parent, that's ok, but all the traversal is by using what's on the stack and adding to the stack using the left and right child links.