Tree-Structure does not inherit generics - java

My goal is to create a tree-like object structure.
For this i created a class named Node (I removed the implementation because the problem still persists without it):
public class Node<S> {
public Node<S> addChild(Node<S> node) {
return this;
}
}
Important to know is that i want to define the generic type S only in the root node, all child nodes should automatically inherit from the root node.
Something like this:
new Node<String>().addChild(
new Node<>().addChild(
new Node<>()
)
)
I restricted the addChild method to only accept Nodes with the same generic type S,
so as far as i know my child node should know that it's generic type S has to be (in this example) String. However it seems like the generic type S gets lost after instantiating a new Node, because it gives me the following Exception:
error: incompatible types: Node<Object> cannot be converted to Node<String>

The use of <> requires type inference, and the argument of the first
addChild must be a Node, and just passing new Node<>() would do - infering from the return type.
But chaining to .addChild(new Node<>()) cannot infer anything, can only provide Node<Object>. So: one cannot use <>.
The problem is (of course) that you want addChild to return the head of the list, and keep adding to the tail of the list.
Normal practice is not to create Node instances, but just use the S values.
public class Node<S> {
private S value;
private Node<S> next;
public Node(S value) {
this.value = value;
}
public static <T> void print(Node<T> root) {
if (root == null) {
System.out.println("empty");
return;
}
System.out.print(root.value);
System.out.print(" --> ");
print(root.next);
}
public static <T> Node<T> addAll(T... values) {
Node<T> root = null;
Node<T> previous = null;
for (T value : values) {
Node<T> current = new Node<>(value);
if (root == null) {
root = current;
} else {
previous.next = current;
}
previous = current;
}
return root;
}
public static void main(String[] args) {
Node<String> root = Node.addAll("a", "b", "c", "d");
print(root);
}
}
Comparable to Collections.addAll or List.of. If you keep a Node<S> last field, you could indeed create something like:
public void addLast(S value) {
last.next = new Node<>(value);
}
This also shows a serious problem of the class: an empty list is not a Node.
One could use Optional<Node<S>> or a special constant for an empty list EMPTY - without value.
The normal solution is to have a container:
public class List<S> {
private class Node {
...
}
private Node<S> root;
private Node<S> last;
private int size;
public List<S> addLast(S value) {
Node<S> current = new Node<>(value);
if (root == null) {
root = current;
last = current;
} else {
last.next = current;
}
last = current;
++size;
return this;
}
private int size() {
return size;
}
...
}
Now everything fits.
List<String> nodes = new List<>()
.addLast("a")
.addLast("b")
.addLast("c")
.addLast("d");
After feedback, when wanting Node references.
Then discard chaining, and make Node public again.
public Node<S> addLast() {
addLast(null);
}
public Node<S> addLast(S value) {
Node<S> current = new Node<>(value);
if (root == null) {
root = current;
last = current;
} else {
last.next = current;
}
last = current;
++size;
return last;
}
List<String> nodes = new List<>()
Node<String> a = nodes.addLast();
Node<String> b = nodes.addLast();
var c = nodes.addLast();
var d = nodes.addLast();
One could use var for shortness.

What you are trying to do is something like this
public class Node<T> {
private Node<T> child;
private T data = null;
public Node (T data) {
this.data = data;
}
public T getData() {
return data;
}
public Node<T> getChild() {
return child;
}
public void addChild(Node<T> child) {
this.child = child;
}
#Override
public String toString() {
return "this node's data: " + data + "; has child? " + (child != null);
}
public static void main(String[] args) {
Node<String> root = new Node<> ("parent");
Node<String> child = new Node<>("child");
root.addChild(child);
System.out.println(root);
System.out.println(child);
}
}
If you were to execute this, it will output
this node's data: parent; has child? true
this node's data: child; has child? false
this node's data: 0; has child? false
this node's data: 1; has child? false
Notice how I can create nodes of type String and Integer. However, this class is incomplete if you want to create a tree structure. The implementation of "tree" will depend on what kind of tree you are talking about. For example, a simple binary tree will have two children at most. Other types of trees could have more children. Also, adding nodes to a tree might require balancing the tree.
Now, to your question, this answer suffices. I was able to demonstrate the use of generics to create Node objects of type T.

Related

Root node always becoming NULL when traversing

In this binary tree implementation
I've tried to create an object from the BinaryTree class and thus insert elements and access them in order. While debugging it seems it's always returning root as NULL and thus the traversal fails.
I don't understand what I'm missing here. Where is my mistake?
public class BinaryTree{
public static class Node{
int value;
Node left;
Node right;
public Node(int data){
this.value = data;
left = null;
right = null;
}
}
Node root;
BinaryTree() {
root = null;
}
public Node addrecursive(Node current,int value){
if(current==null){
return new Node(value);
}else
if(value<current.value){
int n=current.value;
current.left=addrecursive(current.left,value);
}else
if(value>current.value){
int n=current.value;
current.right=addrecursive(current.right,value);
}else
{
return current;
}
return current;
}
public void add(int value) {
Node n = null;
if(root==null)
root = addrecursive(root, value);
else
n = addrecursive(n, value);
}
private void createBinaryTree(){
BinaryTree bt = new BinaryTree();
bt.add(6);
bt.add(4);
bt.add(8);
bt.add(3);
bt.add(5);
bt.add(7);
bt.add(9);
return;
}
private boolean containsNodeRecursive(Node current, int value) {
if (current == null) {
return false;
}
if (value == current.value) {
return true;
}
return value < current.value
? containsNodeRecursive(current.left, value)
: containsNodeRecursive(current.right, value);
}
public boolean containsNode(int value) {
return containsNodeRecursive(this.root, value);
}
public void traverseInOrder(Node node) {
if (node != null) {
traverseInOrder(node.left);
System.out.print(" " + node.value);
traverseInOrder(node.right);
}
}
void printInorder() { //wrapper class for access without passing node
traverseInOrder(root);
}
public static void main(String [] args){
BinaryTree bt = new BinaryTree() ; //object of class
bt.createBinaryTree(); //creating the binary tree within that object
Boolean b = bt.containsNode(7);
System.out.println(b);
System.out.println("\nInorder traversal of binary tree is " );
bt.printInorder();
}
}
There are several issues:
In addrecursive the variable n is a local reference that is unrelated to your root. So whatever n = addrecursive(n, value); does with the null that you pass as argument, it doesn't do anything with the linked list that starts at root.
It is actually quite simple... Your addrecursive function should only do:
public void add(int value) {
root = addrecursive(root, value);
}
The assignment to root is only really needed when root was null, but it doesn't hurt to always make that assignment. It is however important to pass root as argument, as that is the lead for where to append the new node.
createBinaryTree creates a new local instance of BinaryTree (which is already strange, since this already is an instance), adds nodes to it, and then just discards that local instance -- all work done for nothing. There are different ways to solves this, but I would make this method a static method, and have it return the BinaryTree instance that it populated. The caller in main should then take that returned tree and assign it to its own variable:
// Static!
private static BinaryTree createBinaryTree(){
BinaryTree bt = new BinaryTree();
bt.add(6);
bt.add(4);
bt.add(8);
bt.add(3);
bt.add(5);
bt.add(7);
bt.add(9);
return bt; // return the work that was done
}
public static void main(String [] args){
// Call static function to get the reference to the new tree
BinaryTree bt = createBinaryTree();
Boolean b = bt.containsNode(7);
System.out.println(b);
System.out.println("\nInorder traversal of binary tree is " );
bt.printInorder();
}

Calling a function with a getter as parameter doesn't retain refrence?

I am having an issue with my code, I am making a Binary Search Tree data structure, and when I call a function with a node's child, then assign a value to that child within the function, it doesn't update the node's child.
//*** Pseudo-ish Code ***
class BSTNode {
private BSTNode lChild;
private BSTNode rChild;
private int key;
public BSTNode(int key) {
this.lChild = null;
this.rChild = null;
this.key = key;
}
//getters and setters for each field ^
}
class BST {
private BSTNode root;
public BST() {
this.root = null;
}
public void insert(BSTNode currentNode, int value) {
BSTNode newNode = new BSTNode(value);
if (currentNode == null) {
currentNode = newNode;
if (this.root == null) {
this.root = currentNode;
}
} else {
//ignore the newNode == currentNode value statement right now
if (newNode.getValue() < currentNode.getValue()) {
insert(currentNode.getlChild(), value);
} else if (newNode.getValue() > curNode.getValue()) {
insert(curNode.getrChild(), value);
}
}
}
//getters and setters
}
I still want to figure out the code myself, but I am curious as to why if I were to run this code with:
BST testBST = new BST();
testBST.insert(testBST.getRoot(), 10);
testBST.insert(testBST.getRoot(), 7);
System.out.print(testBST.getRoot());
System.out.print(" ");
System.out.print(testBST.getRoot().getlChild());
This will output 10 then a NullPointerException. I understand this is because somehow the 7 didn't get allocated as 10's lChild, but I don't know why? Is it a scope issue I am having, or is it because I call recursively with the getlChild() in my insert function that I don't have access to the actual private lChild field?
NOTE: I was using sysout to debug my code, and I noticed the recursion does work, and it does assign the 7 properly to currentNode, but then once the function is done running, it is like currentNode no longer references the lChild of the initial root node.
The problem is here:
BSTNode newNode = new BSTNode(value);
Each time computer is calling the recursive method insert() , it is creating a new BSTNode(). You just want to add one new BSTNode() each time but it is creating nodes again and again. For example, You want to add 3 and for this it has to call insert() 4 times. Instead of creating only 1 node it will be creating 4 nodes.
What I have done, apart of removing some errors, I have created the recursive insertValue() method in BSTNode class. So you dont have to keep track of currentNode every time you call this method. As, every Node will be calling its own insertValue() method.
//*** Pseudo-ish Code ***
class BSTNode
{
public BSTNode lChild;
public BSTNode rChild;
public int key;
public BSTNode(int key)
{
this.lChild = null;
this.rChild = null;
this.key = key;
}
/* Create INSERT function in BSTNode class so that you dont have to give the "CurrentNode" everytime
you call this method, Now you just have to pass the "Key"*/
public void insertValue(int insertValue)
{
if(insertValue < key)
{
if(lChild == null)
lChild = new BSTNode(insertValue);
else
lChild.insertValue(insertValue);
}
else if(insertValue > key)
{
if(rChild == null)
rChild = new BSTNode(insertValue);
else
rChild.insertValue(insertValue);
}
else;
}
}
class BST
{
private BSTNode root;
public BST()
{
this.root = null;
}
// just create the root if not present else it'll call the recursive method of BSTNode class
public void insert(int value)
{
if(root == null)
root = new BSTNode(value);
else
root.insertValue(value);
}
// you didn't provide these methods so i wrote my own just to get your code runing
public BSTNode getRoot()
{
return root;
}
public int getRootValue()
{
return root.key;
}
}
public class BSTMain
{
public static void main(String[] args)
{
BST testBST = new BST();
testBST.insert(10);
testBST.insert(7);
System.out.print(testBST.getRootValue());
System.out.print(" ");
System.out.print(testBST.getRoot().lChild.key);
}
}
NOTE: I have added some methods like getRoot() just to get your code working, as you haven't provided them.

Adding nodes to a list in ascending order with Java

Is there a way to use the compareTo function when comparing objects, I'm not sure if it's just for Strings. I am trying add an node into its correct position in ascending order.
heres where I declare my attributes/constructor
private Node<E> head; //refers to the head of the node
private int size; // keeps track of the size of the list
// default constructor which creates empty ordered list
public OrderedList(){head = null; size = 0;}
Heres my insert function
public void insert(Object o)
{
Node n = new Node(o, null); // creates new node
// Node for first element greater than or equal
Node current = head.getLink();
Node before = head; // Node for right before the next one is found
// checks to see if list is empty
if(size == 0)
{
head = n;
}
// checks if element is smaller than the head
else if (o.compareTo(head.o) < 0)
{
n.getLink() = head;
head = n;
}
}
here is my node class
package project.pkg3;
public class Node<T>
{
private Object data;
private Node link;
public Node(Object o, Node l){data = o; link = l;}
public void setData(Object o){data = o;}
public void setLink(Node l){link = l;}
public Object getData(){return data;}
public Node getLink(){return link;}
}
I'm getting an error message when trying to check whether the element belongs in the front on this line
else if (o.compareTo(head.o) < 0)
telling me that it cannot find the symbol, which I'm not sure what that means
Im also getting another error message on this line
n.getLink() = head;
this one is telling me that it's an unexpected type
If your linked list must be sorted using compareTo(), then you need to make sure that the underlying data is comparable.
public class Node<T extends Comparable>
{
private T data;
private Node<T> link;
public Node(T o, Node<T> l) { data = o; link = l; }
public void setData(T o) { data = o; }
public void setLink(Node<T> l) {link = l; }
public T getData() { return data; }
public Node<T> getLink() { return link; }
}
Then this block
else if (o.compareTo(head.o) < 0)
{
n.getLink() = head;
head = n;
}
should be changed into this:
else if (
(o.getData() != null) ?
(o.getData().compareTo(head.getData()) < 0) :
(head.getData().compareTo(o.getData()) > 0)
)
{
n.setLink(head);
head = n;
}
I didn't look at your linked list implementation though, so I have no idea the other stuff are correct.
Your node class should implement java.lang.Comparable interface and override its compareTo() method as per your logic.
public class Node<T extends Comparable<T>>{
}
Your argument object would implement Comparable interface. For eg:
public class Name implements Comparable<Name> {
private String str1;
public int compareTo(Name o) {
//your logic here to compare object with itself
return this.str1.compareTo(o.str1);
}
}

Find child in non-binary tree (recursively)

I have TreeNode class - implementation of the node of the non-binary tree (List<TreeNode> children).
I need find the first node with the given data among the children of this. I wrote some method, but there is some problem obviously (java.lang.AssertionError: Failed to find a child with not-null data: expected:<2> but was:<null>). (if data is null I need to return first child with null data).
public TreeNode findChild(Object data) {
if (data == null) {
Iterator<TreeNode> a = getChildrenIterator();
TreeNode tmp;
while (a.hasNext()) {
tmp = a.next();
if (tmp.getData()==null) return tmp;
tmp.findChild(data);
}
}else
{
Iterator<TreeNode> a = getChildrenIterator();
TreeNode tmp;
while (a.hasNext()) {
tmp = a.next();
if (data.equals(tmp.getData())) return tmp;
tmp.findChild(data);
}
}
return null;
}
Your recursion isn't correct. You should be returning the result of tmp.findChild() if it returns a non-null value.
You also need to consider whether you're supposed to be implementing a depth-first or breadth-first search.
The problem is within the fact you don't return the result of the recursive call.
Maybe the following code will help:
import java.util.*;
public class TreeNode
{
// Constructor
public TreeNode()
{
children = new ArrayList<TreeNode>();
node_data = null;
}
// Get node's data
public Object getData()
{
return (node_data);
}
// Set node's data
public void setData(Object data)
{
node_data = data;
}
// Find the node with specified data
// Return null if not found
public TreeNode findChild(Object data)
{
// Maybe we're the one we're looking for
if (equalData(data))
return (this);
// Search within child nodes
Iterator<TreeNode> it;
TreeNode node;
it = getChildrenIterator();
while (it.hasNext())
{
node = findChild(it.next());
if (node != null)
return (node);
}
// If we get here, we didn't find it
return (null);
} // findChild
// Return whether specified data equals ours
private boolean equalData(Object data)
{
if (node_data == null)
return (data == null);
else
return (node_data.equals(data));
}
// Return iterator over node's children
private Iterator<TreeNode> getChildrenIterator()
{
return (children.iterator());
}
// The node's children
private List<TreeNode> children;
// The node's data
private Object node_data;
} // class TreeNode

How to make my custom linked list to use generics?

I need to implement custom linked list using generics.
Here is what I've done
public class Node {
Node next;
Object data;
public Node(Object data) {
next = null;
this.data = data;
}
public Object getData() {
return data;
}
public void setData(Object dataValue) {
data = dataValue;
}
public Node getNext() {
return next;
}
public void setNext(Node nextValue) {
next = nextValue;
}
}
public class LinkedList {
private Node head;
private int size;
public LinkedList() {
head = new Node(null);
size = 0;
}
public void add(Object data) {
Node node = new Node(data);
Node current = head;
while (current.getNext() != null) {
current = current.getNext();
}
current.setNext(node);
size++;
}
public int getSize() {
return size;
}
public String toString() {
Node current = head.getNext();
String elements = "";
while (current != null) {
elements += "[" + current.getData().toString() + "]";
current = current.getNext();
}
return elements;
}
}
public class Main {
public static void main(String[] args) {
System.out.println("Hello there!");
LinkedList list = new LinkedList();
list.add("First node");
list.add("Second node");
list.add("Third node");
list.add("Fourth node");
list.add("Fifth node");
System.out.println("Linked list contains " + list.getSize() + " nodes");
System.out.println("Here they are: " + list);
}
}
I have no idea or just didn't quite understand where i should use generics and how? Any ideas?
You start with the Node class; specifically, you make it such that it can contain any type of data.
You do that in this manner:
Introduce a generic type parameter at the class level
public class Node<T> { }
Wherever you have Object, replace it with T.
T data;
Be sure to update references to other Node instances inside so that they're using the same generic argument.
Node<T> next;
Now, you can address the issues in your LinkedList class in a similar way.
Introduce a generic type parameter at the class level
public class LinkedList<T> { }
Change the argument of add from Object to T.
public void add(T data) { }
Add the generics to your Node instance(s) so that you're not using a raw type.
private Node<T> head;
You should consider going through the Generics tutorial. Specifically, read through the 'Generic Types' section.
Basically, your LinkedList and Node implementations need to be generic by simply declaring them as LinkedList<T> and Node<T>. Once you've changed the classes to be generic, you can then instantiate a parameterized LinkedList, such as:
LinkedList<String> stringList = new LinkedList<>();
The LinkedList is now type-safe and will only allow Strings to be stored.

Categories

Resources