Generic Methods for Linked-list - java

trying to get these 2 methods to work, but I don't have much experience with generics and the concept is confusing a lot.
Anything getFirst(): Returns the value stored in the first node in the list. It should print an error message and return null if the list is empty.
Anything getLast(): Returns the value stored in the last node in the list. It should print an error message and return null if the list is empty.
Here's my code: (The methods above appear at the bottom)
public class Node<Anything>{
private Anything data;
private Node next;
Node(Anything a, Node n)
{
data = a;
next = n;
}
public Anything getData()
{
return this.data;
}
public Anything setData(Anything newData)
{
Anything oldData = this.data;
this.data = newData;
return oldData;
}
public void setNext(Node newNext)
{
this.next = newNext;
}
public Node getNext()
{
return this.next;
}
}
-----------------------------------------------
public class CS2LinkedList<Anything>{
private Node first;
private Node last;
public CS2LinkedList()
{
first = null;
}
public boolean isEmpty()
{
return (first == null);
}
public void addFirst(Anything d)
{
Node temp = first;
first = new Node(d,temp);
}
public void clear()
{
first = null;
}
public boolean contains(Anything value)
{
for (Node curr = first; curr != null; curr = curr.getNext())
{
if (value.equals(curr.getData())){
return true;
}
}
return false;
}
public String toString()
{
StringBuilder result = new StringBuilder(); //String result = "";
for (Node curr = first; curr != null; curr = curr.getNext())
result.append(curr.getData() + "->"); //result = result + curr.data + "->";
result.append("[null]");
return result.toString(); //return result + "[null]";
}
public int size()
{
int size = 0;
for (Node curr = first; curr != null; curr = curr.getNext()){
size++;
if (first==null){
size = 0;
}
}
return size;
}
// ------------------------ Question begins here ------------------------
public Anything getFirst()
{
if (first != null){
// What should I return here? I tried returning first, (Anything) first, but none of them seems to work.
}
else{
return null;
}
}
public Anything getLast()
{
if (first != null){
// Same here
}
else{
return null;
}
}

The class Node has a type parameter, but in your class CS2LinkedList you are using it without the type parameter. You're using it as a raw type. Raw types only exist in Java for backward compatibility with very old Java versions, which didn't have generics. You shouldn't use raw types (unless absolutely necessary because you have to work with very old code).
Everywhere where you write Node in your class CS2LinkedList, write Node<Anything> instead. For example, declare the member variables like this:
private Node<Anything> first;
private Node<Anything> last;
Write your addFirst method like this:
public void addFirst(Anything d)
{
Node<Anything> temp = first;
first = new Node<>(d,temp);
}
Etcetera.
Then, in you can write your getFirst() method like this:
public Anything getFirst()
{
if (first != null){
return first.getData();
}
else{
return null;
}
}
And similar for the getLast() method.
You also need to modify some of the code in class Node. The constructor parameter and the parameter of the setNext method should also have a type argument:
Node(Anything a, Node<Anything> n)
{
data = a;
next = n;
}
public void setNext(Node<Anything> newNext)
{
this.next = newNext;
}
As well as the return type of the getNext method:
public Node<Anything> getNext()
{
return this.next;
}

Related

I can´t override toString Method [duplicate]

This question already has an answer here:
Java generics - The type parameter String is hiding the type String
(1 answer)
Closed last month.
Hello I have two java classes "List" and "ListPlayground". The problem is i can´t override the toString() Method, because I get this Error:
error: toString() in List cannot override toString() in Object
public String toString() {
^
return type String is not compatible with java.lang.String
where String is a type-variable:
String extends Object declared in class List
List.java:59: error: incompatible types: java.lang.String cannot be converted to String
String string = "";
^
where String is a type-variable:
String extends Object declared in class List
Note: List.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
2 errors
Here is the class I have
public class List<String> {
private class Node {
private String element = null;
private Node next = null;
private Node(String element, Node next) {
this.element = element;
this.next = next;
}
private Node(String element) {
this.element = element;
}
}
private Node head = null;
private Node current = head;
public void prepend(String object) {
head = new Node(object, head);
}
public void append(String object) {
if(head == null) {
head = new Node(object);
return;
}
Node current = head;
while(current.next != null) {
current = current.next;
}
current.next = new Node(object);
}
public String first() {
get(0);
}
public String get(int index) {
Node current = head;
for(int i = 0; i < index; i++) {
current = current.next;
}
return current.element;
}
public int size() {
Node current = head;
int size = 0;
for(; current != null; size++) {
current = current.next;
}
return size;
}
public String toString() {
String string = "";
while(current != null) {
string += head.element + " -> ";
current = head.next;
}
return string;
}
}
Here is the ListPlayground class:
public class ListPlayground {
public static void main(String[] args) {
List<String> stringliste = new List()<>;
stringliste.append("World");
stringliste.append("!");
stringliste.prepend("Hello");
System.out.println("The Length of the List is: " + stringliste.size());
System.out.println("The first Element of the List is: " + stringliste.first());
System.out.println("The element with Index 2 is: " + stringliste.get(2));
System.out.println("The last element is: " + stringliste.get(stringliste.size() - 1));
System.out.println("The whole List is: " + stringliste.toString());
System.out.println("And again the whole List " + stringliste.toString());
}
}
can somebody help me?
I tried to debug my code but I did not succeed. I know that the class "Object" is the superclass of all classes and I have to override the toString() Method, but I do not understand why the toString() method is wrong i the List class?
It's because your generic type is called String, which is shadowing the java.lang.String class. They both extend the Object, but they are fundamentally different.
To fix this problem, call your generic argument something else.
i.e.:
public class List<T> {
private class Node {
private T element = null;
private Node next = null;
private Node(T element, Node next) {
this.element = element;
this.next = next;
}
private Node(T element) {
this.element = element;
}
}
private Node head = null;
private Node current = head;
public void prepend(T object) {
head = new Node(object, head);
}
public void append(T object) {
if(head == null) {
head = new Node(object);
return;
}
Node current = head;
while(current.next != null) {
current = current.next;
}
current.next = new Node(object);
}
public T first() {
get(0);
}
public T get(int index) {
Node current = head;
for(int i = 0; i < index; i++) {
current = current.next;
}
return current.element;
}
public int size() {
Node current = head;
int size = 0;
for(; current != null; size++) {
current = current.next;
}
return size;
}
public String toString() {
String string = "";
while(current != null) {
string += head.element + " -> ";
current = head.next;
}
return string;
}
}
or you could just specify which String you want to return in the toString() method
i.e.:
public java.lang.String toString() {
java.lang.String string = "";
while(current != null) {
string += head.element + " -> ";
current = head.next;
}
return string;
}
Generally I would prefer solution 1) over 2). It's never a good idea to introduce a generic parameter which shadows a class name.
When you use public class List<String>, "String" is used as a generic type and not java.lang.String.
You should change your class declaration and remove the type as you don't need it.
public class List {
... your code here
}
public class List<T> is same as public class List<String> and in both the cases, it is generic type and not a java.lang.String type.
A List<String> class is declared in the code, which syntactically is like declaring a List<T> class where the "T" is called "String."
So when you try to do the override the compiler is like seeing this:
public T toString()
Also in the implemation of the toString method it is very inefficient to use the +=, it uses a StringBuilder instead.

When to initialize a dummy node in a linked list

I am implementing a version of singly linked list in Java with a dummy node.
public class Node{
private String data;
private Node nextNode;
public Node(String data){
this.data = data;
this.nextNode = null;
}
//getters, setters, toString()
}
public class LinkedList {
private Node header;
private Node lastNode;
private int size;
public LinkedList() {
this.header = new Node(null);
this.lastNode = this.header;
size = 0;
}
public void prepend(String data) {
if (data == null || data.trim().length() == 0) {
return;
}
Node newNode = new Node(data);
// when the linked list is empty
if (size == 0) {
this.header.setNext(newNode);
this.lastNode = newNode;
} else { // when the list has nodes
Node existingNode = this.header.getNext();
newNode.setNext(existingNode);
this.header.setNext(newNode);
}
size++;
}
}
I am mainly concentrating on this part.
public LinkedList() {
this.header = new Node(null);
this.lastNode = this.header;
size = 0;
}
When a linked list object is created and initialized, header and last node point to a dummy node.
Would this be an efficient way to implement a linked list? Or, do I have to alter my code in prepend() method as follows?
public void prepend(String data) {
if (data == null || data.trim().length() == 0) {
return;
}
Node newNode = new Node(data);
// when the linked list is empty
if (size == 0) {
this.header = new Node(null);
this.header.setNext(newNode);
this.lastNode = newNode;
} else { // when the list has nodes
Node existingNode = this.header.getNext();
newNode.setNext(existingNode);
this.header.setNext(newNode);
}
size++;
}
Also, is it really necessary to use a dummy node as the header? Can we use the first node itself as the header? Under what circumstances should we be using a dummy node, if at all used?
A dummy node is useful if you want to enforce a non-null constraint for the link fields of the node. Further, it allows to implement all operations without the need to implement special cases for the first and last node, e.g.
public class LinkedList {
static final Node REMOVED = new Node();
public static class Node {
Node next, prev;
String data;
Node() {
next = prev = this;
}
Node(String s, Node n, Node p) {
data = s;
next = n;
prev = p;
}
public Node insertBefore(String s) {
if(next == REMOVED) throw new IllegalStateException("removed node");
Node node = new Node(s, this, prev);
prev.next = node;
prev = node;
return node;
}
public Node insertAfter(String s) {
return next.insertBefore(s);
}
public void remove() {
if(next == REMOVED) throw new IllegalStateException("already removed");
prev.next = next;
next.prev = prev;
next = prev = REMOVED;
}
#Override
public String toString() {
return data;
}
}
final Node content = new Node();
private Node first() {
return content.next;
}
private Node last() {
return content.prev;
}
public Node getFirst() {
Node f = first();
if(f == content)
return null; // or throw new NoSuchElementException(string);
return f;
}
public Node getLast() {
Node f = last();
if(f == content)
return null; // or throw new NoSuchElementException(string);
return f;
}
public Node prepend(String s) {
return first().insertBefore(s);
}
public Node append(String s) {
return last().insertAfter(s);
}
public Node findFirst(String string) {
for(Node n = first(); n != content; n = n.next) {
if(n.data.equals(string)) return n;
}
return null; // or throw new NoSuchElementException(string);
}
public Node findLast(String string) {
for(Node n = last(); n != content; n = n.prev) {
if(n.data.equals(string)) return n;
}
return null; // or throw new NoSuchElementException(string);
}
void printForward() {
for(Node n = first(); n != content; n = n.next) {
System.out.println(n.data);
}
}
void printBackward() {
for(Node n = last(); n != content; n = n.prev) {
System.out.println(n.data);
}
}
}
This is a doubly linked list whose internally used dummy node’s next and prev fields become the “first” and “last” fields of the list. This way, all modification methods only have to operate on the Node class and its next and prev fields and the references to the first and last node are treated the right way automatically. Note how all modification methods settle atop only two implementation methods, insertBefore and remove.
It can be use like
LinkedList l = new LinkedList();
l.append("H").insertAfter("l").insertAfter("l");
l.findFirst("l").insertBefore("e");
l.findLast("l").insertAfter("o");
l.printForward();
System.out.println();
l.getFirst().remove();
l.findFirst("l").remove();
l.getFirst().remove();
l.getLast().insertBefore("r");
l.getFirst().insertBefore("d");
l.append("W");
l.printBackward();
for example. For a single linked list, a dummy node might be less useful. If, like in your example, you’re not drawing a benefit from it but have all the special case handling, you should not use a dummy node which only makes the code even more complicated.

how to do Junit for shallow/deep copy of LinkedList

hello there i did the deep copy and the shallow copy is suggested by the user AndyMan and now i did the JUnit and im having a slight problem making those tests:
1.deep copy method
public ListNode<E> deep_clone() {
first = deep_clone(first);
ListNode<E> copy = new ListNode<>(first);
return copy;
}
private static Node deep_clone(Node head) {
if (head == null) {
return null;
}
Node temp = new Node(head.getData());
temp.setNext(deep_clone(head.getNext()));
return temp;
}
Edit
many thanks for AndyMan for suggesting this shallow copy method:
private static Node shallow_clone(Node head) {
if (head == null)
return null;
Node temp = new Node(head.getData());
temp.setNext(head.getNext()); // Just copy the reference
return temp;
}
but one question though how to Junit both the deep and shallow copy methods?
i did the following and i got a failed Junit test:
#Test
public void test_shallow_clone(){
ListNode<Integer> list =new ListNode<>();
for (int i = 0; i < 10; i++)
list.insert(i);
ListNode<Integer>cloned =list.shallow_clone();
//assertSame(cloned,list); //failed i dont know why
//assertEquals(cloned, list);//Even though its shallow copy i get that they are not equal!
assertSame(list.getFirst(), cloned.getFirst());
assertTrue(cloned.equals(list));
}
and the test for the deep copy:
#Test
public void test_depp_clone(){
ListNode<Integer> list =new ListNode<>();
for (int i = 0; i < 10; i++)
list.insert(i);
ListNode<Integer>cloned =list.depp_clone();
assertSame(cloned.getFirst(),list.getFirst());//check for same val..
//assertEquals(cloned, list);//this make the test fail..
assertFalse(cloned.equals(list));//okay the are not equal lists this means its deep copy...no implemented equal method :)
}
class ListNode
public class ListNode<E> implements Iterable<E>{
private Node<E> first;
//private Node<E> last;
public ListNode() {
first = null;
//last = null;
}
public ListNode(Node head) {
this.first = head;
//this.last = this.first;
}
public ListNode(E data) {
Node head = new Node(data);
this.first = head;
//this.last = this.first;
}
#Override
public Iterator<E> iterator() {
return new LL_Iterator<>(first);
}
private static class Node<E> {
private E data;
private Node next;
public Node() {
this.data = null;
this.next = null;
}
public Node(E data) {
this.data = data;
next = null;
}
public Node(E data, Node next) {
this.data = data;
this.next = null;
}
public E getData() {
return data;
}
public void setData(E val) {
this.data = val;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
#Override
public String toString() {
return "Node{" + "data=" + data + ", next=" + next + '}';
}
}
private static class LL_Iterator<E> implements Iterator<E> {
private Node<E> curr;//we have to specify the E here because if we dont we have to cast the curr.getData()
public LL_Iterator(Node head) {
curr = head;
}
#Override
public boolean hasNext() {
return curr != null;
}
#Override
public E next() {
if (hasNext()) {
E data = curr.getData();
curr = curr.getNext();
return data;
}
return null;
}
}
public E getFirst(){
if(first==null)
return null;
return first.getData();
}
public boolean addFirst (E data) {
if(data==null)
return false;
Node t= new Node (data);
t.setNext(first);
first=t;
return true;
}
public E getLast() {
if (first==null)
return null;
return getLast(first).getData();
}
private static<E> Node<E> getLast(Node<E> head) {
if (head == null) {
return null;
}
Node temp = head;
if (temp.getNext() != null) {
temp = getLast(temp.getNext());
}
return temp;
}
//insertion....Wie setLast
public boolean insert(E data) {
if(data==null)
return false;
first = insert(first, data);
//last = getLast();
return true;
}
private static <E> Node insert(Node head, E data) {
if (head == null) {
return new Node(data);
} else {
head.setNext(insert(head.getNext(), data));
}
return head;
}
public void printList(){
LL_Iterator it= new LL_Iterator(first);
printUsingIterator(it,it.next());
}
private static<E> void printUsingIterator (LL_Iterator it, E data){
//VERDAMMT MAL RHEINFOLGE DER ANWEISUNGEN MACHT UNTERSCHIED
System.out.print(data+"->");
if (!it.hasNext()) {
System.out.print(it.next()+"\n");//THIS WILL PRINT NULL!!!
return;
}
printUsingIterator(it,it.next());
}
public int size() {
return size(first);
}
private static int size(Node head) {
if (head == null) {
return 0;
} else {
return 1 + size(head.getNext());
}
}
public boolean contains(E data) {
return contains(first, data);
}
public static <E> boolean contains(Node head, E data) {
if (head == null || data == null) {
return false;
}
if (head.getData().equals(data)) {
return true;
}
return contains(head.getNext(), data);
}
public int countIf(E t) {
return countIf(first, t);
}
private static <E> int countIf(Node head, E t) {
if (head == null ||t ==null) {
return 0;
}
if (head.getData().equals(t)) {
return 1 + countIf(head.getNext(), t);
}
return countIf(head.getNext(), t);
}
//TODO: WHY IM GETTING HERE AN OVERRIDE REQUEST FROM THE COMPILER??
//answer because im overriding the damn clone() of the list class which is shallow clone
public ListNode<E> depp_clone() {
first = depp_clone(first);
ListNode<E> copy = new ListNode<>(first);
return copy;
}
private static Node depp_clone(Node head) {
if (head == null) {
return null;
}
Node temp = new Node(head.getData());
temp.setNext(depp_clone(head.getNext()));
return temp;
}
public ListNode shallow_clone (){
ListNode<E> cloned=new ListNode<>(shallow_clone(first));
return cloned;
}
private static Node shallow_clone(Node head) {
if (head == null)
return null;
Node temp = new Node(head.getData());
temp.setNext(head.getNext()); // Just copy the reference
return temp;
}
Say head points to node0 which points to node1:
head = node0 => node1
In a deep copy, create two new nodes 7 and 8:
deepCopy = node7 => node6
In a shallow copy, create one new node 7 and copy reference to original node:
shallowCopy = node7 => node1
private static Node shallow_clone(Node head) {
if (head == null) {
return null;
}
Node temp = new Node(head.getData());
temp.setNext(head.getNext()); // Just copy the reference
return temp;
}
If the original node1 is changed, it will affect both the original and the shallow copy. it will not affect the deep copy.
Now for the terminology. What has been described is how to deep copy or shallow copy a node. It does not really make sense to shallow copy a linked list, because you are really just shallow coping a single node. Of course you can deep copy the list.
If it were an array, rather than a linked list, then you could shallow or deep copy.
To test these, override equals() and hashCode(). I would consider two lists equal if they have the same values. For two nodes to be equal, they should have the same value, and the rest of the list should be equal. If you don't override equals(), the implementation in Object is used. Object uses a bitwise comparison requiring the same references. You may want to look this up.
Also when overriding equals(), hashCode() needs to be overriden too. This is not directly related to the question, so you may want to look it after.
ListNode equals() and hashCode():
#Override
public boolean equals(Object otherObject) {
// Objects are equal if they have the same value, and next has the same value
if (otherObject instanceof ListNode) {
ListNode other = (ListNode)otherObject;
return first.equals(other.first);
}
else {
return false;
}
}
#Override
public int hashCode() {
return first.hashCode();
}
Node equals() and hashCode():
#Override
public boolean equals(Object otherObject) {
// Objects are equal if they have the same value, && next has the same value
if (otherObject instanceof Node) {
Node other = (Node)otherObject;
return data.equals(other.data) && ((next == null && ((Node) otherObject).getNext() == null) || next.equals(((Node) otherObject).next));
}
else {
return false;
}
}
#Override
public int hashCode() {
return data.hashCode();
}

Inserting at the end of a LinkedList

public class LinkedList<T>
{
private Node head;
private int size;
public LinkedList()
{
}
public void addToHead(T value) // create new node, make new node point to head, and head point to new node
{
if (head == null)
{
head = new Node(value,null);
}
else
{
Node newNode = new Node(value,head);
head = newNode;
}
size++;
}
public boolean isEmpty()
{
return head == null;
}
public int size()
{
return size;
}
public void removeHead()
{
head = head.next;
size--;
}
public void addToTail(T value)
{
if (isEmpty())
{
System.out.println("You cannot addtoTail of a emptyList!");
}
else
{
System.out.println(value);
Node current = head;
System.out.println("we are pointing to head: "+current);
while (current.getNext() != null) // loop till the end of the list (find the last node)
{
System.out.println("we are now pointing to: "+current.getElement());
current = current.getNext();
}
System.out.println("We are at the last node:"+current); // its working
System.out.println("it should point to null:"+current.getNext()); // its working
current.setNext(new Node(value,null)); // make it point to our new node we want to insert
System.out.println(current.getNext()); // it is pointing to the new node.. yet the node is not actually inserted (local variable problem? )
size++;
}
}
public String toString()
{
String output = "";
if (!isEmpty())
{
Node current = head;
output = "";
while (current.getNext() != null)
{
output += current.toString()+ "->";
current = current.getNext();
}
}
return output;
}
protected class Node
{
private T element;
private Node next;
public Node()
{
this(null,null);
}
public Node(T value, Node n)
{
element = value;
next = n;
}
public T getElement()
{
return element;
}
public Node getNext()
{
return next;
}
public void setElement(T newElement)
{
element = newElement;
}
public void setNext(Node newNext)
{
next = newNext;
}
public String toString()
{
return ""+element;
}
}
}
So I have written this linkedlist class, and every method works except addtoTail. For example say I create a instance of my linkedlist class, and call addToHead(5), then addtoTail(6) and use my toString method to print out the linkedlist, it only contains 5->. I debugged the addToTail and everything seems to be pointing to the correct locations, yet for some reason it does not add the new node (6) to the list. Hopefully I explained that clearly. I am probably missing something really simple (I even drew it on paper to visualize it but do not see the problem).
Your addToTail function is probably fine. I think the culprit is your toString function. In particular, in this snippet:
while (current.getNext() != null)
{
output += current.toString()+ "->";
current = current.getNext();
}
Your condition terminates the loop before reaching the end. What you actually want is:
while(current != null) {
....
}

Need help on unchecked operations java

I am learning algorithms myself, and I tried to implement LinkedList in Java with generic types from scratch. I had a version with Object which works well, but when I updated it with generic types, it gives warnings. Can anybody help where does the "unchecked or unsafe operations" come from?
class LinkedListGeneric <T> {
private Node<T> head;
private int size;
public LinkedListGeneric() {
head = null;
size = 0;
}
public int size() {
return size;
}
public void add (T data) {
if (head == null) {
head = new Node<T> (data);
size = 1;
}
else {
Node<T> temp = new Node<T> (data);
search(size).setNext(temp);
size++;
}
}
public void add (T data, int position) {
if (position > size + 1 || position <= 0) {
System.out.println ("error.");
return;
}
Node<T> temp = new Node<T> (data);
if (position == 1) {
temp.setNext(head);
head = temp;
return;
}
Node<T> prev = search(position - 1);
temp.setNext(prev.getNext());
prev.setNext(temp);
}
public void delete (int position) {
if (position > size || position <= 0) {
System.out.println ("error.");
return;
}
if (position == 1) {
size--;
head = head.getNext();
return;
}
Node<T> prev = search(position - 1);
prev.setNext(prev.getNext().getNext());
size--;
}
public T getValue (int position) {
if (position > size || position <= 0) {
System.out.println ("error.");
return null;
}
Node<T> temp = search(position);
return temp.getData();
//return search(position).getData();
}
public int searchData(T data) {
Node<T> temp = head;
int position = 1;
boolean flag = false;
while (temp != null) {
if (temp.getData() == data) {
flag = true;
break;
}
else {
temp = temp.getNext();
position++;
}
}
if (flag) return position;
else return -1;
}
public void print() {
Node<T> temp = head;
int position = 1;
while (temp != null) {
System.out.println("Node " + position + ": " + temp.getData());
temp = temp.getNext();
position++;
}
}
private Node<T> search (int position) {
Node temp = head;
while (position > 0) {
temp = temp.getNext();
}
return temp;
}
private class Node<T> {
private T data;
private Node<T> next;
public Node() {
this.data = null;
next = null;
}
public Node(T data) {
this.data = data;
next = null;
}
public T getData() {
return data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
}
The problem I see is your Node.getNext call is returning a Node instead of a Node<T>. This is equivalent to the method returning Node<Object> instead of the generic type.
So, you should change:
public Node getNext() {
return next;
}
to
public Node<T> getNext() {
return next;
}
Although sbochin's answer will fix some of your warnings, doing the following will fix all of them:
Replace all instances of T within your Node class, including the one in the class declaration, with T2.
Change the return of getNext to Node<T2>
Change the argument type in setNext to Node<T2>.
Change the type of temp in search to Node<T>.
You might also want to add an #SuppressWarnings("unused") to public Node() since that also generates a compiler warning.
You might also want to make your Node class a static class as none of it's methods depend on the LinkedListGeneric<T> object it is in.
Completely alternatively, you could just get rid of the type parameter from Node, which gets rid of all your warnings except the unused warning. You'd have to keep your class nonstatic however.

Categories

Resources