From a Generic Tree To a Domain Specific Tree - java

I want to use a domain specific tree DomainTree consisting of Domain specific Nodes DomainNode, but keep all generic functions in template classes Tree and Node. First I started with the templates Tree<T> and Node<T> (where T is the type of a nodes data). The DomainTree was then working with the Node<T> interface, which was not what I wanted. It should work on DomainNode objects instead.
To cope with that, I changed the generic tree's template parameter to Tree<N extends Node<?>> (the implementation below). Now I can work with the DomainNode by instantiating the tree as DomainTree<DomainNode>.
Still, I get a compilation error at (1) because getChildren() returns a list of Node<T>, which doesn't seem to be convertible to a list of N, though I made sure that N extends Node<?>.
Why is this not working and how can I design it, so that the DomainTree can work with DomainNodes?
Generic Tree
import java.util.ArrayList;
import java.util.List;
class Tree<N extends Node<?>> {
public N rootElement;
public List<N> toList() {
List<N> list = new ArrayList<N>();
walk(rootElement, list);
return list;
}
private void walk(N element, List<N> list) {
list.add(element);
List<N> children = element.getChildren(); // (1) Cannot convert from List<Node<T>> to List<T>
for (N data : children) {
walk(data, list);
}
}
}
class Node<T> {
public T data;
public List<Node<T>> children;
public List<Node<T>> getChildren() {
if (this.children == null) {
return new ArrayList<Node<T>>();
}
return this.children;
}
public void addChild(Node<T> child) {
if (children == null) {
children = new ArrayList<Node<T>>();
}
children.add(child);
}
}
Problemspecific Tree
class DomainTree extends Tree<DomainNode> {
public void build() {
for (DomainNode node : toList()) {
// process...
}
}
}
class DomainNode extends Node<String> {
}

The problem with the code as it stands is that for a given Node<T>, the compiler has no way of knowing that the type of the List returned from toList() is the same Node<T> as the class itself.
What you need is a self-referencing generic type:
class Node<T, N extends Node<T, N>> {
public T data;
public List<N> children;
public List<N> getChildren() {
return children == null ? Collections.<N>emptyList() : children;
}
public void addChild(N child) {
if (children == null) {
children = new ArrayList<N>();
}
children.add(child);
}
}
Now the type returned from toList() is the same type as the type itself.
Then DomainNode becomes:
class DomainNode extends Node<String, DomainNode> {
//
}
And the signature of of Tree changes slightly to become:
class Tree<N extends Node<?, N>> {
And your usage example now compiles:
class DomainTree extends Tree<DomainNode> {
public void build() {
for (DomainNode node : toList()) {
// process...
}
}
}
I added in a couple of other efficiencies too.

generics hold some surprises if you are not really into it. At first keep in mind that there is a type erasure and the compiler and the runtime thus see different things. Roughly spoken this also limits the compiler abilities in analyzing source code.
Note that there is really a difference between a List<Node<N>> and a List<N>. Hence even with N extends Node<?> the assignment 'List children = element.getChildren();' is inherently broken.
Furthermore with your declaration of Tree<N extends Node<?>>, you would expect that you can write something like List<Node<?>> l2 = element.getChildren();. Unfortunately this does not work due to some subleteties of generics. For example if you change your code to class Tree<N extends Node<N>> (this is probably not what you intended) you can write List<Node<N>> l2 = element.getChildren();.
I recommend to study the Sun Certified Java Programmer Study Guide for Java 6 (or a newer version) or something similar which is really helpful about generics.
From your code I got the impression that you mix different abstraction layers as there is the T data in the Node<T> class and in the for each loop the element is called N data. However in the loop you have a node N extends Node<?> which would be completely different from the T data. Hence the intention for your code remains a bit unclear for me. A working draft if your code as fixed version is here (Eclipse Luna, JDK 6)
package generics.tree;
import java.util.ArrayList;
import java.util.List;
class Tree<T> {
public Node<T> rootElement;
public List<Node<T>> toList() {
List<Node<T>> list = new ArrayList<Node<T>>();
walk(rootElement, list);
return list;
}
private void walk(Node<T> element, List<Node<T>> list) {
list.add(element);
List<Node<T>> children = element.getChildren(); // (1) Cannot convert from List<Node<T>> to List<T>
for (Node<T> data : children) {
walk(data, list);
}
}
}
class Node<T> {
public T data;
public List<Node<T>> children;
public List<Node<T>> getChildren() {
if (this.children == null) {
return new ArrayList<Node<T>>();
}
return this.children;
}
public void addChild(Node<T> child) {
if (children == null) {
children = new ArrayList<Node<T>>();
}
children.add(child);
}
}
class DomainTree extends Tree<String> {
public void build() {
for (Node<String> node : toList()) { // changed!
// process...
}
}
}
class DomainNode extends Node<String> {
}

Related

Java: Turning a tree into a stream

One of the advantages of streams is that you can avoid visiting the whole structure for some operations, like anyMatch or filter+findFirst.
However, if you have your own data structure, depending on how you turn it into a stream you may end up visiting it all anyway.
What is the right way to turn a custom tree data type into a stream?
Consider the following example:
interface Tree{
void forEach(Consumer<Integer> c);
}
final class EmptyTree implements Tree{
public void forEach(Consumer<Integer> c){}
}
interface NonEmptyTree extends Tree{}
record Leave(int label) implements NonEmptyTree{
public void forEach(Consumer<Integer> c){
System.out.println("In forEachLeave "+label);
c.accept(label);
}
}
record Node(NonEmptyTree left, NonEmptyTree right) implements NonEmptyTree{
public void forEach(Consumer<Integer> c){
left.forEach(c); right.forEach(c);
}
}
The two main ways to turn a tree into a stream would be
var sb=Stream.<Integer>builder();
myTree.forEach(sb);
sb.build()
or
Stream.of(myTree).mapMulti(Tree::forEach)
However, both of them call forEach, thus both of them will visit all the tree (and call the prints for all the labels, in this example).
How do you implement a .stream() method in the Tree type so that it would not even visit the whole tree if it is not needed? (because of .anyMatch, for example)
Ok, I sorted it.
I'm quite sure that what I'm doing is pretty standard with immutable trees
(parent fields only make sense in mutable trees)
Here is my result, for reference for future programmers doing streams on immutable trees.
The class TreeIterator<E> is the one really relevant to this ordeal.
I could make nested classes to be able to make more stuff private, but as a code example I think it is more clear in this non nested form.
interface Tree<E> extends Iterable<E>{
Tree<E> and(Tree<E> other);
default Tree<E> left(){ return empty(); }
default Tree<E> right(){ return empty(); }
default E label(Supplier<E> orElse){ return orElse.get(); }
#SuppressWarnings("unchecked")
static <E> Tree<E> empty(){ return (Tree<E>)EmptyTree.empty; }
static <E> Tree<E> leaf(E label){ return new Leaf<E>(label); }
default Stream<E> stream(){ return StreamSupport.stream(spliterator(), false); }
}
final class EmptyTree<E> implements Tree<E>{
public Tree<E> and(Tree<E> other){ return other; }
private EmptyTree(){} //Singleton pattern: only one EmptyTree can exists
static final Tree<?> empty = new EmptyTree<>();
public Iterator<E> iterator(){ return List.<E>of().iterator(); }
public String toString(){ return "<EMPTY>"; }
}
interface NonEmptyTree<E> extends Tree<E>{
Leaf<E> itAdvance(ArrayList<NonEmptyTree<E>> stack);
default Tree<E> and(Tree<E> other){
if (!(other instanceof NonEmptyTree<E> net)){ return this; }
return new Node<E>(this, net);
}
}
record Leaf<E>(E label) implements NonEmptyTree<E>{
public E label(Supplier<E> orElse){ return label; }
public Leaf<E> itAdvance(ArrayList<NonEmptyTree<E>> stack){ return this; }
public Iterator<E> iterator(){ return List.<E>of(label).iterator(); }
public String toString(){ return label+""; }
}
record Node<E>(NonEmptyTree<E> left, NonEmptyTree<E> right) implements NonEmptyTree<E>{
public Node{ assert left!=null && right!=null; }//null is not a valid tree
public Leaf<E> itAdvance(ArrayList<NonEmptyTree<E>> stack){
stack.add(right);
return left.itAdvance(stack);
}
public Iterator<E> iterator(){ return new TreeIterator<E>(this); }
public String toString(){ return "("+left+", "+right+")"; }
}
class TreeIterator<E> implements Iterator<E>{
private final ArrayList<NonEmptyTree<E>> stack = new ArrayList<>(32);
public boolean hasNext(){ return !stack.isEmpty(); }
public TreeIterator(Node<E> n){ stack.add(n); }
public E next(){
if(stack.isEmpty()){ throw new NoSuchElementException(); }
var last=stack.remove(stack.size()-1);
return last.itAdvance(stack).label();
}
}
Looking at record definition Leave(int label) implements NonEmptyTree, I have two questions:
Did you mean "leaf"?
A tree consists of nodes (either a leaf or an internal node), but a node or leaf do not implement a tree, i.e., they are not are specific type of a tree. Are you sure about your node/leaf/tree implementation?
I would recommend a simple implementation like this one here: https://www.baeldung.com/java-binary-tree
When it comes to stream, you have two options:
Implement your own Stream-enabled class (see discussion here)
Provide a method that returns a (specific) stream, e.g. filtered.
Keep in mind that there are many different trees out there, e.g. red–black tree, n-ary tree, AVL Tree, B-Tree ...

Java question on runtime type checking in implemented method

I am designing some java objects to represent graphs and trees. For my use case I will be using both data types but I also want my graph algorithms to work on my trees.
import java.util.List;
public interface Node<T> {
T getValue();
List<? extends Node<T>> getNeighbors();
void addNodes(List<? extends Node<T>> nodes);
}
public interface TreeNode<T> extends Node<T> {
List<? extends TreeNode<T>> getChildren();
void addChildren(List<? extends TreeNode<T>> treeNodes);
#Override
default List<? extends Node<T>> getNeighbors() {
return getChildren();
}
#Override
default void addNodes(List<? extends Node<T>> nodes) {
if(nodes.getClass().isInstance(getChildren().getClass())) {
addChildren((List<? extends TreeNode<T>>) nodes);
} else {
throw new RuntimeException("Type error!");
}
}
}
My question is about how I'm dealing with addNodes method in the Node interface in the TreeNode interface. The addNodes method has to be in the Node interface because I want to allow people to write code that can add nodes to graphs. However, I also don't want people to add arbitrary nodes to a tree node(for example adding a graph node to a tree node).
In order to prevent this, I'm checking the type of nodes at runtime and throwing an exception if the type is not right. I'm just wondering if this is the best way to accomplish what I want or if there is a better practice?
Thanks for helping :)
If I understand correctly, what you want is (a variation on) the so-called curiously recurring template pattern. The Node type needs to be parameterized not only by its payload type (T) but also by the type of nodes it can be used with. So you want something like:
public interface Node<T, N extends Node<T, N>> {
T getValue();
List<N> getNeighbors();
void addNodes(List<N> nodes);
}
public interface TreeNode<T> extends Node<T, TreeNode<T>> {
List<TreeNode<T>> getChildren();
void addChildren(List<TreeNode<T>> treeNodes);
#Override
default List<TreeNode<T>> getNeighbors() {
return getChildren();
}
#Override
default void addNodes(List<TreeNode<T>> nodes) {
addChildren(nodes);
}
}
Demo (shows compilation only): https://ideone.com/44qrmX
The way I see it, Node is a container for some data. Tree and Graph are two ways to maintain relationships between Nodes. So perhaps three classes should be defined:
import java.util.List;
public class Node<T> {
private T value;
public Node(T value) { this.value = value; }
T getValue() { return value; }
}
public abstract class Tree<T> {
private Node<T> root;
public abstract List<? extends Node<T>> getChildren();
public abstract void addChildren(List<? extends Node<T>> nodes);
public Tree(Node<T> root) { this.root = root; }
}
public abstract class Graph<T> {
private Node<T> root;
public abstract List<? extends Node<T>> getNeighbors();
public abstract void addNeighbors(List<? extends Node<T>> nodes);
public Graph(Node<T> root) { this.root = root; }
}
EDIT: If you want to have shared traversal algorithms, you can put them in separate classes and have the Tree and Graph use similar semantics like this:
// common semantics for node containers
public interface NodeContainer<T> {
List<? extends Node<T>> getRelatedNodes();
}
public abstract class Tree<T> implements NodeContainer<T> {
... // same as above
#Override
public List<? extends Node<T>> getRelatedNodes() {
return getChildren();
}
}
public class NodeContainerTraversal {
public void bfs (NodeContainer<?> container) {
...
}
}

Extendable double-linked tree implementation in Java

I want to extend an existing double-linked tree implementation by some extra data.
Therefor I could refactor the basic TreeNode implementation, but I want to have a separate extended TreeNode implementation, because in my real-world szenario building-up an ExtandedTreeNode will be much more expensive than building-up the basic TreeNode, and the extra data is only necessary for some use-cases.
Rudimental Code
Here my first rudimental approach for an extendable double-linked tree implementation in Java:
Basic tree node interface:
interface TreeNode
{
// tree node getters:
TreeNode getParent();
List<? extends TreeNode> getChildren();
// tree node setters:
void setParent(TreeNode parentNode);
void addChild(TreeNode childNode);
// some basic operations:
boolean isSelectable();
// [...]
}
Extended tree node interface:
interface ExtandedTreeNode extends TreeNode
{
// narrow types of tree node getters of super-interface:
#Override
ExtandedTreeNode getParent();
#Override
List<? extends ExtandedTreeNode> getChildren();
// narrowing types of tree node setters of super-interface is not possible!
// some additional operations:
boolean isRemoveable();
// [...]
}
Basic tree node implementation:
class TreeNodeImpl implements TreeNode
{
private TreeNode parent;
private List<TreeNode> children = new ArrayList<TreeNode>();
private boolean isSelectable;
//
// implement tree node getters:
//
#Override
public TreeNode getParent()
{
return parent;
}
#Override
public List<? extends TreeNode> getChildren()
{
return children;
}
//
// implement tree node setters:
//
#Override
public void setParent(TreeNode parent)
{
this.parent = parent;
}
#Override
public void addChild(TreeNode childNode)
{
children.add(childNode);
}
//
// implement basic operations:
//
#Override
public boolean isSelectable()
{
return isSelectable;
}
// [...]
}
Extended tree node implementation:
class ExtandedTreeNodeImpl implements ExtandedTreeNode
{
private ExtandedTreeNode parent;
private List<ExtandedTreeNode> children = new ArrayList<ExtandedTreeNode>();
private TreeNode treeNode;
private boolean isRemoveable;
public ExtandedTreeNodeImpl()
{
treeNode = new TreeNodeImpl();
}
//
// implement tree node getters:
//
#Override
public ExtandedTreeNode getParent()
{
return parent;
}
#Override
public List<? extends ExtandedTreeNode> getChildren()
{
return children;
}
//
// implement tree node setters:
//
#Override
public void setParent(TreeNode parent)
{
this.parent = (ExtandedTreeNode) parent; // <--- How to avoid this type cast!!
}
#Override
public void addChild(TreeNode childNode)
{
children.add((ExtandedTreeNode) childNode); // <--- How to avoid this type cast!!
}
//
// implement basic operations by delegating to composite TreeNode:
//
public boolean isSelectable()
{
return treeNode.isSelectable();
}
// [...]
//
// implement additional operations:
//
#Override
public boolean isRemoveable()
{
return isRemoveable;
}
// [...]
}
Question
For me the type hierarchy looks great for the read-only and non-tree-node-specific methods, but it leaks for the setters setParent(..) and addChild(..). Particularly the risky typecast to ExtandedTreeNode is quite evil and I want to get rid of it.
I thought about extracting the setParent(..) and addChild(..) methods to another two separate Interfaces like TreeNodeWriteable and ExtandedTreeNodeWriteable, but maybe there are some better design solutions.
Does anyone know a design pattern or blue print which could solve my problem with the writeable tree-node-specific setters?
You can use generics. Define your tree node as the following:
interface TreeNode<N extends TreeNode> {
N getParent();
List<N> getChildren();
void setParent(N parentNode);
void addChild(N childNode);
}
Now your TreeNodeImpl will look like:
class TreeNodeImpl implements TreeNode<TreeNode>
While ExtendedTreeNodeImpl will be defined like follows:
class ExtendedTreeNodeImpl implements ExtendedTreeNode<ExtendedTreeNode>
The parametrized methods into these classes will use specific types: TreeNode and ExtendedTreeNode, so no casting is needed.
You could use the self type pattern. The downside is that all your code gets littered with type arguments that (most of the time) you don't really need.
Example:
interface TreeNode<S extends Node<S>> { // S is the self type
void setParent(S parent);
void addChild(S child);
}
interface ExtendedTreeNode extends Node<ExtendedTreeNode> {}
Edit:
Related blog post by Stephen Colebourne

using compareTo in Binary Search Tree program

I've been working on this program for a few days now and I've implemented a few of the primary methods in my BinarySearchTree class such as insert and delete. Insert seemed to be working fine, but once I try to delete I kept getting errors. So after playing around with the code I wanted to test my compareTo methods. I created two new nodes and tried to compare them and I get this error:
Exception in thread "main" java.lang.ClassCastException: TreeNode cannot be cast to java.lang.Integer
at java.lang.Integer.compareTo(Unknown Source)
at TreeNode.compareTo(TreeNode.java:16)
at BinarySearchTree.myComparision(BinarySearchTree.java:177)
at main.main(main.java:14)
Here is my class for creating the nodes:
public class TreeNode<T> implements Comparable
{
protected TreeNode<T> left, right;
protected Object element;
public TreeNode(Object obj)
{
element=obj;
left=null;
right=null;
}
public int compareTo(Object node)
{
return ((Comparable) this.element).compareTo(node);
}
}
Am I doing the compareTo method all wrong? I would like to create trees that can handle integers and strings (seperatly of course)
To be sure that the element indeed is a comparable object, and avoid all the casts, you could do something like this:
public class TreeNode<T extends Comparable<? super T>>
implements Comparable<TreeNode<T>> {
protected TreeNode<T> left, right;
protected T element;
public TreeNode(T obj) {
element = obj;
left = null;
right = null;
}
#Override
public int compareTo(TreeNode<T> node) {
return element.compareTo(node.element);
}
}
For an usage example:
TreeNode<Integer> node1 = new TreeNode<Integer>(2);
TreeNode<Integer> node2 = new TreeNode<Integer>(3);
System.out.println(node1.compareTo(node2));
The above snippet prints -1 on the console.
compareTo method is applied against TreeNode (passed as node parameter), while you compare it with this.element, which is an Object contained in the TreeNode. Simply change to:
return ((Comparable) this.element).compareTo(node.getElement());
assuming you have getElement method.
Try
public <T> int compareTo(Object node)
{
return ((Comparable) this.element).compareTo( ( TreeNode<T> ) node ).element);
}

Write a tree class in Java where each level has a unique object type

I need to write a tree class in Java where each level has a unique object type. The way it is written below does not take advantage of generics and causes alot of duplicate code. Is there a way to write this with Generics ?
public class NodeB {
private String nodeValue;
//private List<NodeB> childNodes;
// constructors
// getters/setters
}
public class NodeA {
private String value;
private List<NodeB> childNodes;
// constructors
// getters/setters
}
public class Tree {
private String value;
private List<NodeA> childNodes;
// constructors
// tree methods
}
This is simplistic implementation, but enough to give general idea:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class GenericNode {
public static abstract class AbstractNode<V, N> {
private V value;
private List<N> children;
public AbstractNode(V value, N... children) {
this.value = value;
this.children = children != null ? Arrays.asList(children)
: Collections.<N> emptyList();
}
public V getValue() {
return value;
}
public List<N> getChildren() {
return children;
}
public int getNumberOfChildren() {
return children.size();
}
#Override
public String toString() {
return value.toString() + "->" + children.toString();
}
}
// leaf node type, ignore type of children
public static class NodeB extends AbstractNode<String, Object> {
public NodeB(String value, Object... nodes) {
super(value, nodes);
}
}
// example of typical node in the mid of tree
public static class NodeA extends AbstractNode<String, NodeB> {
public NodeA(String value, NodeB... nodes) {
super(value, nodes);
}
}
// top level node type
public static class Tree extends AbstractNode<String, NodeA> {
public Tree(String value, NodeA... nodes) {
super(value, nodes);
}
}
#SuppressWarnings({ "rawtypes", "unchecked" })
public static <V, N extends AbstractNode> int getNodeCount(
AbstractNode<V, N> node) {
int nodeCount = node.getChildren().size();
for (N child : node.getChildren()) {
nodeCount += getNodeCount(child);
}
return nodeCount;
}
public static void main(String[] args) {
NodeB nodeB1 = new NodeB("Leaf node 1");
NodeB nodeB2 = new NodeB("Leaf node 2");
NodeA nodeA = new NodeA("Node with children", nodeB1, nodeB2);
NodeA emptyNodeA = new NodeA("Empty node");
Tree tree = new Tree("Tree", nodeA, emptyNodeA);
System.out.println(tree);
System.out.println(1 + getNodeCount(tree));
}
}
You could make N and V types implement specific interfaces so it will be possible to call some common operations on values and/or children.
EDIT: updated implementation with recursive method for node count retrieval
All you need is a Pair<A, B>. Example of trees:
Pair<A, Pair<B, C>>
Pair<Pair<A, B>, Pair<C, D>>
Pair<Pair<Pair<A, B>, Pair<C, D>>, Pair<Pair<E, F>, Pair<G, H>>
ps: don't do this. :)
This is an ideal spot for everything inheriting from "Node", but even that is unnecessary.\
What you probably want is a single generic "Node" object that contains references to your different classes (use composition before inheritance).
At that point, each of your different classes probably has something that can be done to them (otherwise why are they all in the same data structure?) Have them implement a common interface with this common functionality. The node class can delegate to this interface, or some other class can extract the class by this interface and act on it.
This would be better than trying to force something to also BE a node--do one simple thing and do it well.
--edit--
I can't really add an example that is relevant to you because you didn't post anything about your scenario.
But let's say that you have these different classes A, B * C. First of all are they related AT ALL aside from all being children of Object? Let's say they all implement interface "Iface". (If not, you can just replace Iface with "Object", but this really implies a bad design.)
Anyway, your "Node" object is just one object--
public class Node {
private List<node> children;
private Iface myObject;
... setters, getters, tree implementation, tree navigation, related garbage...
}
Now this is enough to create your tree. One thing that you might be able to do to make things smoother, have "Node implements Iface" and delegate any calls to it's object. For instance, if Iface contains an eat(Food foodtype) method, your node could implement Iface and have a method:
public void eat(Food foodtype) {
myObject.eat(foodtype);
}
This would make the "Node" class act as though it was the class it contained.
By the way--another relatively good idea at this point would be to make myObject "private final" and ensure it is not null in the constructor. That way you would always know it was set and none of your delegated members would have to do null checks.
I don't think generics are going to help you much in this case. Instead of having a different class for each level in the tree. What about one node class that has children and store a different class on each level. That should help eliminate a lot of the duplication.
I'm fairly new to Java, so this might have issues I'm not aware of, but it seems to work on a simple level at least.
Define your main Node class - this one will be the root of the tree.
public class NodeA {
private String _value;
private ArrayList<NodeA> _children;
private int _depth;
public NodeA (String value, int depth) {
_value = value;
_children = new ArrayList<NodeA>();
_depth = depth;
}
//probably want getters for _children and _value here
//this makes a new child, with its type depending on the depth of the tree it will
//be placed at. NodeB and NodeC will both inherit from NodeA
public void add(String value) {
switch (_depth) {
case 0:
_children.add(new NodeB(value, _depth+1));
break;
case 1:
_children.add(new NodeC(value, _depth+1));
break;
}
}
The add() method is going to create a new child for the node using the specified value. If you initialize the root of the tree as a NodeA with depth 0, you can add children to nodes and the tree should end up populated so that the next level contains all NodeB's, and the next all NodeC's. The code for NodeB and NodeC is super simple and could be replicated to create an arbitrary amount of Node levels (here is that code).
public class NodeB extends NodeA {
public NodeB(String value, int depth) {
super(value, depth);
}
//nothing else needed!
The code for NodeC is identical, except for the obvious replacements of B's with C's.
Hope this helps / is the kind of answer you wanted!

Categories