Java parallel streams: there's a way to navigate a binary tree? - java

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).

Related

Linked list and adding elements to the end of the list

I need to create linked list of rectangles. Im given the class files of rectangleandpointclasses, and need to writeRectNodeandRectList`.
This is RectNode:
public class RectNode
{
private RectangleA _rect;
private RectNode _next;
public RectNode(RectangleA r)
{
_rect = r;
_next = null;
}
public RectNode(RectangleA r,RectNode n)
{
_rect = r;
_next = n;
}
public RectNode(RectNode other)
{
_rect = other._rect;
_next =other._next;
}
public RectangleA getRect()
{
return _rect;
}
public RectNode getNext()
{
return _next;
}
public void setRect(RectangleA r)
{
_rect = r;
}
public void setNext (RectNode next)
{
_next = next;
}
}
And this is part of RecList which I have a problem with:
public class RectList
{
private RectNode _head;
public RectList()
{
_head = null;
}
public void addRect(RectangleA t)
{
RectNode value = new RectNode(t,null);
RectNode next = new RectNode(t,_head);
while(next.getNext() != null)
{
next = next.getNext();
}
}
I want the order to be first-in first-out, but managed only first-in last-out by this:
public void addRect(RectangleA t)
{
RectNode next = new RectNode(t,_head);
_head = next;
}
So how I do that the way I need? I tried running trough the list by next.getNext() until the
next is null, but can`t figure out by code and implement it.
These are the issues in addRect:
There is no assignment of value to anything that relates to the list, so the node is not added.
There is no provision to update _head when it was null
If it was intended to create a dummy node that sits in from of _head (which can be a valid approach), then this idea is destroyed by walking away from that node in the loop: you have for ever lost the reference to that dummy node, yet you would need it to update _head (in case it was null)
There are several ways to do this, and I understand from your code that you want to introduce a dummy node, that sits in front of the current _head. But then you would need another reference to stay there, one that is not modified by the loop.
I would also use different variable names. value gives the impression that it is about a node's value, but this is not the case: it is a node -- the one to be added -- so I'd just call it newNode if you really need the variable at all. The name next suggests that it refers to something that precedes it, but that seems irrelevant here. As its purpose is to identify the tail of the list, why not call it tail?
1. Solution using a dummy node
public void addRect(RectangleA t)
{
final RectNode preHead = new RectNode(t, _head); // This reference will stay here
RectNode tail = preHead; // This reference will traverse the list
while (tail.getNext() != null)
{
tail = tail.getNext();
}
// Now create and append the new node immediately after the tail node:
tail.setNext(new RectNode(t, null));
// Set the new head (in case it was null, this is relevant)
_head = preHead.getNext();
}
2. Solution without dummy node
Although the solution with the dummy node does not have to distinguish between the case of an empty and non-empty list, you can avoid the use of the dummy node when you do deal separately with these cases:
public void addRect(RectangleA t)
{
if (_head == null) { // Special case, the only one where _head must change
_head = new RectNode(t, null);
} else { // The list is not empty, and _head will not change
RectNode tail = _head;
while (tail.getNext() != null)
{
tail = tail.getNext();
}
// Now create and append the new node immediately after the tail node:
tail.setNext(new RectNode(t, null));
}
}

How to set up a constructor for a Iterator class with a stack?

I need help setting up this constructor for my Iterator class. The directions are as follows:
The constructor should create a new stack and push its node parameter onto it, followed by
all left children accessible from the parameter. Consider a case in which the tree consists
only of left children (essentially a linked list). The node with the highest value (root) would
be pushed first and be on the bottom of the stack, followed by its left child just above it in the
stack, followed by its left child, and so on until the leaf, which would contain the lowest value
in the tree. When popping nodes from the stack, they would contain values from lowest to
highest… an in-order traversal.
I am not sure how to create a new stack with the node in the parameter being a type BSTNode type.
Here is my code:
public static class Iterator<E>
{
private Stack<BSTNode<E>> stack;
public Iterator(BSTNode<E> node)
{
}
public boolean hasNext()
{
if(stack.peek() != null)
{
return true;
}
else
{
return false;
}
}
public E next()
{
stack.pop();
E value;
value = (E) stack.pop();
return value;
}
}
As of right now, just ignore the other two methods, I just need help with the Iterator method. I'll figure those out later. Thank you.
I found out my problem was in a different class and method. I set it up as this and I want to know if this is the correct way of doing it.
The instructions for this method is
to create and return an instance of the static nested Iterator class that will be used to iterate through the elements in the tree. The tree's root should initially be passed to the iterator constructor.
Here is the following code I did for that method:
public Iterator<E> iterator()
{
return new Iterator<>(root);
}
root is the top of the binary search tree. It is in that class as a private variable.
Here's how I set it up.
This is just the public that is above the class. Not inside the class. I just return a new Iterator with root being the top value.
public Iterator<E> iterator()
{
return new Iterator<>(root);
}
Then inside the class below it, I create a new stack and have that stack push the nodes and the nodes to the left of it as long as it isn't null.
public static class Iterator<E>
{
private Stack<BSTNode<E>> stack;
public Iterator(BSTNode<E> node)
{
this.stack = new Stack<>();
while (node != null)
{
stack.push(node);
node = node.left;
}
}
public boolean hasNext()
{
return !stack.isEmpty();
}
public E next()
{
BSTNode<E> goodDays = stack.pop();
E result = goodDays.data;
if (goodDays.right != null)
{
goodDays = goodDays.right;
while (goodDays != null)
{
stack.push(goodDays);
goodDays = goodDays.left;
}
}
return result;
}
}

How can I return a node with a specific value in a BST?

I have to make a so called "Hit Balanced Tree". The difference is that as you can see, my node class has an instance variable called numberOfHits, which increments anytime you call contains method or findNode method. The point of this exercise is to have the nodes with highest hit count on the top, so the tree basically reconstructs itself (or rotates). Root has the highest hit count obviously.
I have a question regarding a method I have to make, that returns the node with highest hit count. I will later need it to make the tree rotate itself (I guess, at least that's the plan). Here is my node class. (All the getters of course)
public class HBTNode<T> {
private HBTNode<T> left;
private HBTNode<T> right;
private T element;
private int numberOfHits;
public HBTNode(T element){
this.left = null;
this.right = null;
this.element = element;
this.numberOfHits = 0;
}
What I have so far is this:
public int findMaxCount(HBTNode<T> node) {
int max = node.getNumberOfHits();
if (node.getLeft() != null) {
max = Math.max(max, findMaxCount(node.getLeft()));
}
if (node.getRight() != null) {
max = Math.max(max, findMaxCount(node.getRight()));
}
return max;
}
This works fine, except it returns an integer.I need to return the node itself. And since I have to do this recursively, I decided find the biggest hit count and then subsequently using this method in another method that returns a node, like this(it's probably really inefficient, so if you have tips on improvement, I am listening):
public int findMaxCount() {
return findMaxCount(root);
}
public HBTNode<T> findMaxCountNode(HBTNode<T> node) {
if (node.getNumberOfHits() == this.findMaxCount()) {
return node;
}
if (node.getLeft() != null ) {
return findMaxCountNode(node.getLeft());
}
if (node.getRight() != null) {
return findMaxCountNode(node.getRight());
}
return null;
}
I call the method like this:
public HBTNode<T> findMaxCountNode() {
return findMaxCountNode(root);
}
It returns null even though I think it should be fine, I am not that good at recursion so obviously I am missing something. I am open to any help, also new suggestions, if you have any about this exercise of mine. Thanks a lot.
Test code:
public static void main(String[] args) {
HBTree<Integer> tree = new HBTree<Integer>();
tree.add(50);
tree.add(25);
tree.add(74);
tree.add(19);
tree.add(8);
tree.add(6);
tree.add(57);
tree.add(108);
System.out.println(tree.contains(108)); //contains method increases the count by one
System.out.println(tree.contains(8));
System.out.println(tree.contains(8));
System.out.println(tree.contains(108));
System.out.println(tree.contains(8));
System.out.println(tree.contains(108));
System.out.println(tree.contains(108));
System.out.println(tree.contains(108));
System.out.println(tree.findMaxCountNode());
}
Current output: true
true
true
true
true
true
true
true
null
Expected output: true
true
true
true
true
true
true
true
Element: 108
Left child: 6 //this is just a toString, doesn't matter at this point
Right child: null
Number of hits: 5
Seems like your two functions should look like the following. What I'm assuming here is that these functions, which are defined inside the HBTNode class, are designed to find the highest hit-count node below itself:
public HBTNode<T> findMaxCountNode(HBTNode<T> node) {
return findMaxCountNode(node, node);
}
public HBTNode<T> findMaxCountNode(HBTNode<T> node, HBTNode<T> maxNode) {
HBTNode<T> currMax = (node.getNumberOfHits() > maxNode.getNumberOfHits()) ? node : maxNode;
if (node.getLeft() != null ) {
currMax = findMaxCountNode(node.getLeft(), currMax);
}
if (node.getRight() != null) {
currMax = findMaxCountNode(node.getRight(), currMax);
}
return currMax;
}
public int findMaxCount(HBTNode<T> node) {
HBTNode<T> maxNode = findMaxCountNode(node);
if (maxNode != NULL)
return maxNode.getNumberOfHits();
else
return -1;
}
Let me know if there are any issues, this is off the top of my head, but I thought it would be helpful to point out that the "integer" version of your method should just use the "Node finding" version of the method. The method you wrote to find the maximum value is quite similar to the one I wrote here to find the maximum node.

Retrieving all the nodes from a given tree in Java

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;
}

Linked List in Java method implementation

Now Im preparing for coding interview and I have 1 question regarding linked list in Java. Can you tell me some reliable sources from which I can learn and practice the basic linked list methods. I liked this one: www.cs.cmu.edu/~adamchik/15-121/lectures/Linked%20Lists/code/LinkedList.java but I'm confused with some method implementations. For example the method E get(int pos) returns NOT node but the data E contained in the node at position pos. While here http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/util/LinkedList.java#LinkedList the method Node node(int index) returns the node at that position (not the data contained in it). Which implementation should I follow?
Well the Data Structures is a very conceptual and context based discipline. The various implementations that exist for each data structure are based on the requirements and scope of the data structure.
One can even argue that the LinkedList implementation of the Collection API is buggy as it doesn't work well if multiple threads work on it concurrently. Then a synchronizedList from the Collections class need to be made or at least an implementation which works well with multiple threads need to be used.
Follow the minimum viable convention that gets you going, as the interviewer won't just ask you a LinkedList implementation. What the interviewer wants to know is if your concepts and coding skills are up to a certain mark or not.
Think of what you can do with a Linked List. For that you'll have to think as to what type of LinkedList you are actually considering as there are many different kinds of LinkedLists, like SinglyLinkedList, DoublyLinkedList, SkipList, etc.
Considering a SinglyLinkedList, your LinkedList implementation should at least have the following methods: add(), remove(), contains(), clear(), size().
Following is my implementation of a SinglyLinkedList:
import java.util.Iterator;
import java.util.StringJoiner;
public class LinkedList<T> implements Iterable<T>
{
private Node head;
private Node tail;
private int size;
private class Node
{
private T value;
private Node next;
public Node(T value)
{
this.value = value;
}
}
public void add(T value)
{
Node node = new Node(value);
if (head == null)
{
head = node;
}
else
{
tail.next = node;
}
tail = node;
++size;
}
public boolean remove(T value)
{
Node previous = null;
Node current = head;
while (head != null)
{
if (current.value.equals(value))
{
if (previous != null)
{
previous.next = current.next;
if (current.next == null)
{
tail = previous;
}
}
else
{
head = current.next;
if (head == null)
{
tail = null;
}
}
--size;
return true;
}
previous = current;
current = current.next;
}
return false;
}
public boolean contains(T value)
{
Node current = head;
while (current != null)
{
if (current.value.equals(value))
{
return true;
}
current = current.next;
}
return false;
}
public void clear()
{
head = null;
tail = null;
size = 0;
}
public int size()
{
return size;
}
#Override
public Iterator<T> iterator()
{
return new Iterator<T>()
{
private Node current = head;
#Override
public boolean hasNext()
{
return current != null;
}
#Override
public T next()
{
Node next = current;
current = current.next;
return next.value;
}
};
}
#Override
public String toString()
{
StringJoiner joiner = new StringJoiner(", ");
for (T value : this)
{
joiner.add(value.toString());
}
return joiner.toString();
}
}
As you can see, my implementation may be different from the implementations that you may find elsewhere. Small differences are not any issue as long as the data structure's concepts aren't radically changed and as long as it works properly with its defined interface.
For disciplines like Data Structures, you have to think for yourself and based on your requirements, use or implement data structures that fit your needs. As far as interviews go, an implementation of a minimum viable data structure is all that you need to show and all that is required. Just make sure that such minimum viable data structure isn't buggy in its context.

Categories

Resources