Can a variable be declared in java using the name of a subclass? I found this piece of code about linked lists very confusing. See, how the head of the list has been declared. Can someone please explain?
class LinkedList
{
Node head; // head of list
/* Linked list Node*/
class Node
{
int data;
Node next;
// Constructor to create a new node
// Next is by default initialized
// as null
Node(int d)
{
data = d;
}
}
}
Yes, an object can indeed contain a reference to another object of the same type as an instance member.
For example, this is the standard class definition of a Linked List Node:
class Node {
int value;
Node next;
... // instance methods follow
}
You have the current node which must point to a reference of the next node in the linked list.
Related
I'm writing my own singly-linked list class for an assignment. I originally had my Node class in the root directory inside its own java file, but it assigns the generic T to obj, so it looks like it has to be nested inside SLList<T>.
My question (unrelated to the assignment): Is there a way to extract the Node class from the outer class, or must it be defined inside the outer class because it inherits the assignment?
public class SLList<T> {
Node head; // Front of the queue
Node tail; // Back of the queue
int count; // The number of elements in the queue
public class Node {
T obj; // The stored object in this node.
Node next; // The reference to the next object, null if final element.
}
...
...
...
If I create Node in an outer class, I run into the following error:
...
...
public T remove() {
// If empty, just return null:
if (count == 0)
return null;
// Set
T obj = head.obj; // ERROR: Object cannot be converted to type T.
head = head.next;
if (--count == 0)
tail = null;
return obj;
}
I need a doubly linked list that can work on different node implementations. Note that I do not want nodes that contain generic data, like DoublyLinkedNode<T>, but something like DoublyLinkedList<N extends DoublyLinkedNode<T>>.
To be precise, I use the list in the general case with standard nodes, but in other parts of my program I need nodes with additional fields. So I implemented the general node as
public class DoublyLinkedNode<T> {
DoublyLinkedNode<T> before, after;
T value;
}
and the special type as
public class DoublyLinkedSpecialNode<T, S> extends DoublyLinkedNode<T> {
S specialValue;
}
Now in my DoublyLinkedList implementation I want to be able to handle both cases at one, because all the code basically fiddles around with the pointers that are obviously common to both implementations.
This gives a few requirements:
1) When I use the special node, I want to be able to return it as the DoublyLinkedSpecialNode type to be able to access the additional fields.
2) The list must use a DoublyLinkedNode type to access the pointers of the nodes.
3) The list is assigning the pointed-to nodes to other nodes, e.g. head = node.after;, so the type of the pointers in the special node must be the same as the type in the list.
Extending the list makes no sense because then I could not change the return type of the methods. Therefore I tried two ideas without success:
The already mentioned solution: Generic node type that extends from DLN
The list would look like this:
public class DoublyLinkedList<T, N extends DoublyLinkedNode<T>> {
N head, tail;
N tail() {
return tail; // OK
}
void remove(N node) {
if (head == node) {
head = node.after; // Type error
}
...
This solution conflicts with requirement 3), because in the list the type is an N that extends from DLN, but in the node implementation N the pointer is of the type of the base class/interface DLN (the pointer type could theoretically be more general than N).
Base DLN instead of generics
In this case the list works on the base class node and accepts the subclasses because of polymorphism:
public class DoublyLinkedList<T> {
DoublyLinkedNode<T> head, tail;
DoublyLinkedNode<T> tail() {
return tail;
}
void remove(DoublyLinkedNode<T> node) {
if (head == node) {
head = node.after; // OK
}
...
But tail() can only return nodes as the general type, conflicting with 1). I would prefer not to use casting, because I assume it's bad practice (?) but also because the implementation is performance critical. There surely is a better way?
I found another solution that is okay-ish, not very performant but more elegant than the last solution.
The idea ist to use only one type of nodes, and wrap the varying content in a generic container. The DLN code looks like this:
public class DoublyLinkedNode<C> {
DoublyLinkedNode<C> before, after;
C content;
public static class ValueContent<T> {
T value;
}
public static class ValueSpecialContent<T, S> extends ValueContent<T> {
S specialValue;
}
}
The list implementation then looks something like this:
public class DoublyLinkedList<C> {
DoublyLinkedNode<C> head, tail;
public DoublyLinkedNode<C> head() {
return head;
}
void remove(DoublyLinkedNode<C> node) {
if (head == node) {
head = node.after;
...
And I can access the special field from the calling class like this:
DoublyLinkedList<SpecialContent<SpecialType>> list;
SpecialType s = list.head().content.specialValue;
There is some overhead because each node has to instantiate that container class, but I think it's still better than casting. I have to check the performance impact.
This question already has answers here:
What does the 'new' keyword actually do in Java, and should I avoid creating new objects?
(6 answers)
Closed 5 years ago.
I keep receiving an error when I'm trying to implement a node with generic data types. the node must be able to take an int input as well as a fraction input. what am i doing wrong? The compiler says that "method Node(A) is undefined for class BinarySearchtree
//creates a generic binary search tree class
public class BinarySearchTree<A> {
//the root of the node, which is the middle value
Node root;
//this constructor will add a node
public void addNode(A userNumber){
Node<A> newNode = Node<A>(A userNumber);
}//end addNode
public class Node<T>{
//this generic variable will become the user input either int or fraction
private T number;
//nodes that will become the left of right child of a parent node
Node<T> leftChild;
Node<T> rightChild;
//a node constructor that will take a generic input
Node(T number){
this.number = number;
}//end node constructor
}//end the Node class
}//end binary search tree
Instead of
Node<A> newNode = Node<A>(A userNumber);
use
Node<A> newNode = new Node<A>(A userNumber);
You don't have any method Node which the compiler gladly tells you about.
I can't understand primitive-wrapper overhead with generics.
ex.
In Data Structure below, Why 24 byte Overhead isn't added to each item, instead it's added once for N inputs.
Question in other way, Why the overall memory space isn't 96N instead of 24 + 72N or why 24 added once.
public class GenericMysteryBox<Item> { // 16(object overhead)
private Node first; // 8 (reference)
private class Node { // 16(object overhead)
// 8 (inner class overhead)
private Item item; // 8 (reference to Integer)
// 24(Integer)
private Node next; // 8 (reference)
private Node prev; // 8 (reference)
} // -------
// 24 + 72N ~ 72N
}
Because the class declaration for Node (while an inner class) isn't mutable between instances. That is, every instance of GenericMysteryBox contains a Node that (after type erasure) has an Object reference and two Node references.
This is exactly the same behaviour as if Node were declared as a non-private non-inner class (ignoring the visibility of Node).
Consider,
class Node<Item> {
private Item item;
private Node next;
private Node prev;
}
public class GenericMysteryBox<Item> {
private Node<Item> first;
}
creating a doubly linked list with one node that points to itself
public DList(){
Dnode sentinel= new DNode(sentinel, null, sentinel);
}
for reference, Dnode constructor takes DNode(Dnode p, Object 0, Dnode n)
Is this valid code?
No, this is not valid.
You can't cant use sentinel variable in the expression that defines it.
You can however have a constructor, which makes the previous and next elements be itself (this):
class DList {
DList previous, next;
public DList() {
previous = this;
next = this;
}
}