We've been asked to implement a Linked Set in java. Below is my attempt, it has all the methods we are asked to write, but the method remove calls a null pointer exception without fail. Try as I might I can't seem to figure it out, any help much appreciated.
import java.util.*;
class LinkedSet<T> {
private static class Node<T> {
private T item;
private Node<T> next;
Node(T item, Node<T> next) {
this.item = item;
this.next = next;
}
}
private Node<T> head = null;
private int numItems = 0;
int size() {
return (numItems);
}
public boolean add(T t) {
if(contains(t)) return false;
Node<T> newNode = new Node(t, null); //new node to be added
if(numItems==0) {
head = newNode;
numItems++;
return true;
}
Node<T> temp = head;
while(temp.next != null) temp = temp.next;
temp.next = newNode;
numItems++;
return true;
}
public boolean remove(T t) {
if(numItems == 0) return false; //check for empty set
//was tempted to use contains here but would have made it N^2 I think
Node<T> p = head; //t if present
Node<T> pPrev = null; //previous node to p
while(p!=null && !equals(t, p.item)) {
pPrev = p;
p = p.next;
}
//t is present if node p!= null , node p != null ==> t in node p
if(p==null) return false;
else {
pPrev.next = p.next; //null pointer
numItems--;
return true;
}
}
public boolean contains(T t) {
Node<T> temp = head;
for(int i = 0; i < numItems; i++) {
if(equals(temp.item, t)) return true;
temp = temp.next;
}
return false;
}
private boolean equals(T t1, T t2) { //t1, t2 may be null
if(t1!=null) return t1.equals(t2); //learn this
else return t2 == null; //learn this
}
public static void main(String[] args) {
LinkedSet<Integer> test = new LinkedSet<Integer>();
test.add(1);
test.add(2);
test.add(3);
for(int i = 0; i < 10; i ++) {
System.out.println("Testing i = " + i + " - " + test.contains(i));
}
System.out.println(); System.out.println(); System.out.println();
System.out.println(test.remove(1));
}
}
The obvious point is that the first element in the list does not have a previous element. (Some linked list implementations will add a dummy link to handle this more cleanly.)
Look at this portion of the code:
Node<T> p = head; //t if present
Node<T> pPrev = null; //previous node to p
while(p!=null && !equals(t, p.item)) {
pPrev = p;
p = p.next;
}
If equals(t, head.item), then pPrev == null when you leave the while loop and you'll get a null pointer exception later.
Related
This question already has answers here:
How do I print my Java object without getting "SomeType#2f92e0f4"?
(13 answers)
Closed 1 year ago.
I am trying to print out the elements in my ArrayList that looks like
static ArrayList<LinkedList> listy = new ArrayList<>();
I tried to create a function called PrintTest()
public static void pTest() {
String [] top;
for (LinkedList i: listy) {
//i.show();
System.out.println(i.toString());
However, I am still getting when I call printTest()
LinkedList#15975490
LinkedList#6b143ee9
LinkedList#1936f0f5
LinkedList#6615435c
LinkedList#4909b8da
LinkedList#3a03464
LinkedList#2d3fcdbd
LinkedList#617c74e5
Do I need to iterator over this once more? I am confused on how to go about this. Can I override toString()? I can't seem to get it to work
Here is my linkedlist implementation code
public class LinkedList {
Node head;
Node tail;
public String getFirst() {
Node node = head;
if (node.next == null) {
throw new NoSuchElementException();
}
else {
return node.data;
}
}
public void insert(String data) {
Node node = new Node();
node.data = data;
node.next = null;
if (head == null) {
head = node;
}
else {
Node n = head;
while(n.next !=null) {
n = n.next;
}
n.next = node;
}
}
public void insertAtStart(String data) {
Node node = new Node();
node.data = data;
node.next = null;
node.next = head;
head = node;
}
public void insertAt(int index, String data) {
Node node = new Node();
node.data = data;
node.next = null;
if(index == 0) {
insertAtStart(data);
}
else {
Node n = head;
for (int i = 0; i < index-1; i++) {
n = n.next;
}
node.next = n.next;
n.next = node;
}
}
public void deleteAt(int index) {
if (index == 0) {
head = head.next;
}
else {
Node n = head;
Node n1 = null;
for (int i = 0; i < index-1; i++) {
n = n.next;
}
n1 = n.next;
n.next = n1.next;
//System.out.println("n1 " + n1.data);
n1 = null;
}
}
public int size() {
int count =0;
Node pos = head;
while (pos != null) {
count++;
pos = pos.next;
}
return count;
}
public void remove(String s) {
Node node = head;
while (!node.data.equals(s)) {
node = node.next;
}
if (node.next == null) {
node.data = null;
}
else {
node.data = node.next.data;
node.next = node.next.next;
}
//System.out.println("n1 " + n1.data);
}
public void show() {
Node node = head;
while(node.next != null) {
System.out.println(node.data);
node = node.next;
}
System.out.println(node.data);
In java, every class inherits the Object class. In the Object class default definition for the toString method is hashcode. When you are calling toString method, you need to define by yourself.
class LinkedList{
int value;
#Override
public String toString(){
return String.valueOf(value);
}
}
I think you can go through this article to get more understanding.Explanation For toString
I have just seen this wonderful code from this question "Generic Linked List in java" here on Stackoverflow. I was wandering on how do you implement a method remove (to remove a single node from the linkedlist), size (to get the size of list) and get (to get the a node). Could someone please show me how to do it?
public class LinkedList<E> {
private Node head = null;
private class Node {
E value;
Node next;
// Node constructor links the node as a new head
Node(E value) {
this.value = value;
this.next = head;//Getting error here
head = this;//Getting error here
}
}
public void add(E e) {
new Node(e);
}
public void dump() {
for (Node n = head; n != null; n = n.next)
System.out.print(n.value + " ");
}
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<String>();
list.add("world");
list.add("Hello");
list.dump();
}
}
Your implementation of LinkedList for operation remove(), size() and contains()
looks like this:
static class LinkedList<Value extends Comparable> {
private Node head = null;
private int size;
private class Node {
Value val;
Node next;
Node(Value val) {
this.val = val;
}
}
public void add(Value val) {
Node oldHead = head;
head = new Node(val);
head.next = oldHead;
size++;
}
public void dump() {
for (Node n = head; n != null; n = n.next)
System.out.print(n.val + " ");
System.out.println();
}
public int size() {
return size;
}
public boolean contains(Value val) {
for (Node n = head; n != null; n = n.next)
if (n.val.compareTo(val) == 0)
return true;
return false;
}
public void remove(Value val) {
if (head == null) return;
if (head.val.compareTo(val) == 0) {
head = head.next;
size--;
return;
}
Node current = head;
Node prev = head;
while (current != null) {
if (current.val.compareTo(val) == 0) {
prev.next = current.next;
size--;
break;
}
prev = current;
current = current.next;
}
}
}
I am trying to learn data structure, but I ran into the dreaded NullPointerException and I am not sure how to fix it.
My SinglyLinkedList<E> class implements an interface, LinkedList, where I redefined some methods like, add(), get(), contains(), and more.
The NullPointerException happens when I use the clear() method. It points at the method removeLast() under nodeBefore.setNext(null). It also points to the clear() method under remove(head.getElement()).
Also, if there is anything I can improve upon in my code please let me know.
public class SinglyLinkedList<E> implements LinkedList<E> {
private class Node<E> {
public Node<E> next;
public E element;
public Node(E element) {
this.element = element;
}
public Node (E element, Node<E> next) {
this.element = element;
this.next = next;
}
public E getElement() {
return element;
}
public Node<E> getNext() {
return next;
}
public void setElement(E element) {
this.element = element;
}
public void setNext(Node<E> next) {
this.next = next;
}
public String toString() {
return ("[" + element + "] ");
}
}
public Node<E> head;
public Node<E> tail;
public int total;
public SinglyLinkedList() {
this.head = null;
this.tail = null;
this.total = 0;
}
public E get(int index) {
if (index < 0 || index > size()) {
return null;
}
if (index == 0) {
return head.getElement();
}
Node<E> singly = head.getNext();
for (int i = 1; i < index; i ++) {
if (singly.getNext() == null) {
return null;
}
singly = singly.getNext();
}
System.out.println("\n" + singly.getElement());
return singly.getElement();
}
public void add(E element) {
Node<E> singlyAdd = new Node<E>(element);
if (tail == null) {
head = singlyAdd;
tail = singlyAdd;
} else {
tail.setNext(singlyAdd);
tail = singlyAdd;
}
total++;
}
public void display() {
if (head == null) {
System.out.println("empty list");
} else {
Node<E> current = head;
while (current != null) {
System.out.print(current.toString());
current = current.getNext();
}
}
}
public boolean contains(E data) {
if (head == null) {
return false;
}
if (head.getElement() == data) {
System.out.println(head);
return true;
}
while (head.getNext() != null) {
head = head.getNext();
if (head.getElement() == data) {
System.out.println(head);
return true;
}
}
return false;
}
private Node<E> removeFirst() {
if (head == null) {
System.out.println("We cant delete an empty list");
}
Node<E> singly = head;
head = head.getNext();
singly.setNext(null);
total--;
return singly;
}
private Node<E> removeLast() {
Node<E> nodeBefore;
Node<E> nodeToRemove;
if (size() == 0) {
System.out.println("Empty list");
}
nodeBefore = head;
for (int i = 0; i < size() - 2; i++) {
nodeBefore = nodeBefore.getNext();
}
nodeToRemove = tail;
nodeBefore.setNext(null);
tail = nodeBefore;
total--;
return nodeToRemove;
}
public E remove(int index) {
E hold = get(index);
if (index < 0 || index >= size()) {
return null;
} else if (index == 0) {
removeFirst();
return hold;
} else {
Node<E> current = head;
for (int i = 1; i < index; i++) {
current = current.getNext();
}
current.setNext(current.getNext().getNext());
total--;
return hold;
}
}
public int size() {
return getTotal();
}
public boolean remove(E data) {
Node<E> nodeBefore, currentNode;
if (size() == 0) {
System.out.println("Empty list");
}
currentNode = head;
if (currentNode.getElement() == data) {
removeFirst();
}
currentNode = tail;
if (currentNode.getElement() == data) {
removeLast();
}
if (size() - 2 > 0) {
nodeBefore = head;
currentNode = head.getNext();
for (int i = 0; i < size() - 2; i++) {
if (currentNode.getElement() == data) {
nodeBefore.setNext(currentNode.getNext());
total--;
break;
}
nodeBefore = currentNode;
currentNode = currentNode.getNext();
}
}
return true;
}
public void clear() {
while (head.getNext() != null) {
remove(head.getElement());
}
remove(head.getElement());
}
private int getTotal() {
return total;
}
}
For your clear method, I don't see that you do any per element cleanup, and the return type is void, so all you want is an empty list. The easiest way is to simply clear everything, like in the constructor:
public void clear() {
this.head = null;
this.tail = null;
this.total = 0;
}
Another comment:
in contains, you do
while (head.getNext() != null) {
head = head.getNext();
if (head.getElement() == data) {
System.out.println(head);
return true;
}
}
which may have two problems (where the first applies to the entire class),
you compare with == data which compares references, where you probably want to compare values with .equals(data)
Edit: I.e. n.getElement().equals(data) instead of n.getElement() == data.
(Or, if n and data may be null, something like (data != null ? data.equals(n.getElement()) : data == n.getElement())
you use the attribute head as the scan variable which modifies the state of the list. Do you really want that?
The problem arises when you delete the last element within clear: remove(head.getElement());. For some reason, you first remove the head and then the tail. But when calling removeLast, you use the head (which is already null). Within removeLast this is the line, which causes the NullPointerException: nodeBefore.setNext(null);.
My advice would be to write the clear() method as #bali182 has suggested:
public void clear() {
this.head = null;
this.tail = head;
this.total = 0;
}
One advice: if you are writing methods to search or delete entries, you should never use == when dealing with objects (or even better: don't use == at all when dealing with objects). You may want to read this thread.
From within clear method, you are calling remove(head.getElement()); meaning you are trying to call LinkedList's remove method. And since you are overriding each functionality and so is add, you don't maintain internal state of LinkedList and hence you get exception. Code in remove is:
public boolean remove(Object o) {
if (o==null) {
for (Entry<E> e = header.next; e != header; e = e.next) {
if (e.element==null) {
So here since you are not using functionality of LinkedList, header would be null and doing header.next would return NullPointerException.
My task is to implement a circular linked list in java (ascending order) but the problem is that it is going in an infinite loop
I have created a class of Node in which i have define two elements.
public class Node {
public int element;
public Node next;
public class Node {
int element;
Node next;
}
}
Now in the second class of List i have made a insert function i have define a Node head=null in the start and create a new nNode .After that i am checking in the head section if head==null then the first element will be nNode. After inserting the first element i will compare the next element and the head element if the head element is greater than it will shift next and the new nNode will be the head. Since it is the circular linked list it is working but it is also going in an infinite loop.
This is the List class in which i have use the node class variables
public class List {
void insert(int e) {
Node nNode = new Node();
Node tNode = head;
nNode.element = e;
if (head == null)
head = nNode;
else if (head.element > e) {
nNode.next = head;
head=nNode;
} else {
Node pNode = head;
while (tNode.next != head && tNode.element <= e) {
pNode = tNode;
tNode = tNode.next;
}
pNode.next = nNode;
nNode.next = tNode;
tNode.next=head;
}
}
}
I have created on sample program for circular linkedlist which hold name and age of given element.
It has add(), remove() and sorbasedOnAge() (Sorting is implemented by first getting clone and convert it into simple linked list. Then use merge sort so that performance of O(nLogn) could be achieved.)
If you like it don't forget to press like button.
package com.ash.practice.tricky;
import java.util.Collections;
import java.util.LinkedList;
public class CircularLinkedList implements Cloneable{
Node start;
public Node getHead() {
return start;
}
CircularLinkedList setHead(Node startNode) {
start = startNode;
return this;
}
public void add(String name, int age) {
if(name==null) {
System.out.println("name must not be null.");
return;
}
if(start == null) {
Node node = new Node(name,age);
start = node;
node.next = start;
} else {
Node node = new Node(name,age);
Node temp = start;
while(temp.next != start) {
temp = temp.next;
}
temp.next = node;
node.next = start;
}
}
public CircularLinkedList clone()throws CloneNotSupportedException{
return (CircularLinkedList)super.clone();
}
public boolean remove(String name) {
if(name==null) {
return false;
} else if(start==null) {
return false;
} else if(start.getName().equals(name)) {
if(size()>1) {
Node temp = start;
while(temp.next!=start) {
temp = temp.next;
}
temp.next = start.next;
start = start.next;
} else {
start = null;
}
return true;
} else {
Node temp = start;
Node next = null;
Node prev = null;
while(temp.next != start) {
String currName = temp.name;
if(currName.equals(name)) {
next = temp.next;
break;
} else {
temp = temp.next;
}
}
if(next == null) {
return false;
}
prev = temp.next;
while(prev.next!=temp) {
prev = prev.next;
}
prev.next = next;
temp = null;
return true;
}
}
/*
public Node getPrevious(String name, int age) {
Node curr = new Node(name,age);
Node temp = curr;
while(temp.next!=curr) {
temp = temp.next;
}
return temp;
}
*/
public int size() {
int count = 1;
if(start != null) {
Node temp = start;
while(temp.next!=start) {
count++;
temp = temp.next;
}
} else return 0;
return count;
}
public int listSize() {
int count = 1;
if(start != null) {
Node temp = start;
while(temp.next!=null) {
count++;
temp = temp.next;
}
} else return 0;
return count;
}
public void display() {
if(start == null) {
System.out.println("No element present in list.");
} else {
Node temp = start;
while(temp.next != start) {
System.out.println(temp);
temp = temp.next;
}
System.out.println(temp);
}
}
public void displayList() {
if(start == null) {
System.out.println("No element present in list.");
} else {
Node temp = start;
while(temp.next != null) {
System.out.println(temp);
temp = temp.next;
}
System.out.println(temp);
}
}
public Node getPrevious(Node curr) {
if(curr==null) {
return null;
} else {
Node temp = curr;
while(temp.next!=curr) {
temp = temp.next;
}
return temp;
}
}
Node getMiddle() {
Node result = null;
Node temp = start.next;
result = start.next;
Node end = getPrevious(start);
end.next = null;
while(temp.next!=null) {
if(temp.next.next!=null) {
temp = temp.next.next;
result = result.next;
} else {
return result;
}
}
return result;
}
private static CircularLinkedList SortCollections(CircularLinkedList list) {
return SortCollections.doSortBasedOnAge(list);
}
private static class Node {
Node next;
String name;
int age;
Node(String name,int age) {
this.name = name;
this.age = age;
}
String getName() {
return name;
}
int getAge() {
return age;
}
public String toString() {
return "name = "+name +" : age = "+age;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
private static class SortCollections {
static Node mergeSort(Node head) {
if(head == null || head.next == null) {
return head;
}
Node middle = getMiddle(head);
Node nextHead = middle.next;
middle.next = null;
Node left = mergeSort(head);
Node right = mergeSort(nextHead);
Node sortedList = sortedMerged(left, right);
return sortedList;
}
public static CircularLinkedList doSortBasedOnAge(CircularLinkedList list) {
CircularLinkedList copy = null;
try {
copy = list.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
if(copy!=null) {
Node head = copy.getHead();
Node end = copy.getPrevious(head);
end.next = null;
Node startNode = mergeSort(head);
CircularLinkedList resultList = new CircularLinkedList().setHead(startNode);
return resultList;
} else {
System.out.println("copy is null");
}
return null;
}
private static Node sortedMerged(Node a, Node b) {
if(a == null) {
return b;
} else if(b == null) {
return a;
}
Node result = null;
if(a.getAge() > b.getAge()) {
result = b;
result.next = sortedMerged(a, b.next);
} else {
result = a;
result.next = sortedMerged(a.next, b);
}
return result;
}
private static Node getMiddle(Node head) {
Node result = null;
Node temp = head;
result = head;
while(temp.next!=null) {
if(temp.next.next!=null) {
temp = temp.next.next;
result = result.next;
} else {
return result;
}
}
return result;
}
}
public static void main(String[] args) {
CircularLinkedList list = new CircularLinkedList();
Collections.sort(new LinkedList());
list.add("ashish", 90);
list.add("rahul", 80);
list.add("deepak", 57);
list.add("ankit", 24);
list.add("raju", 45);
list.add("piyush", 78);
list.add("amit", 12);
//list.display();
/*System.out.println("---------------- size = "+list.size());
System.out.println(list.remove("deepak"));
//list.display();
System.out.println("---------------- size = "+list.size());
System.out.println(list.remove("ashish"));
//list.display();
System.out.println("---------------- size = "+list.size());
System.out.println(list.remove("raju"));
//list.display();
System.out.println("---------------- size = "+list.size());
list.add("aman", 23);
System.out.println("---------------- size = "+list.size());
list.display();
System.out.println("Previous Node of second node is : "+list.getPrevious(list.start.next));
System.out.println("Previous Node of start node is : "+list.getPrevious(list.start));
System.out.println("Previous Node of piyush node is : "+list.getPrevious("piyush",78));*/
list.display();
System.out.println("---------------- size = "+list.size());
//System.out.println(list.getMiddle());
CircularLinkedList newList = CircularLinkedList.SortCollections(list);
newList.displayList();
System.out.println("---------------- size = "+newList.listSize());
}
}
Let's consider the following situation:
The list contains elements B,C,X. Now you want to insert A and then Z.
void insert(int e) {
Node nNode = new Node(); //the new node, step 1: A, step2: Z
Node tNode = head; //step1: points to B, step2: points to A
nNode.element = e;
if (head == null) { //false in both steps
head = nNode;
head.next = head; //I added this line, otherwise you'd never get a circular list
} //don't forget the curly braces when adding more than one statement to a block
else if (head.element > e) { //true in step 1, false in step 2
nNode.next = head; //A.next = A
head=nNode; //A is the new head, but X.next will still be B
} else {
//you'll enter here when adding Z
Node pNode = head; //points to A because of step 1
//when tNode = X you'll start over at B, due to error in step 1
//the condition will never be false, since no node's next will point to A
//and no node's element is greater than Z
while (tNode.next != head && tNode.element <= e) {
pNode = tNode;
tNode = tNode.next;
}
//in contrast to my previous answer, where I had an error in my thought process,
//this is correct: the node is inserted between pNode and tNode
pNode.next = nNode;
nNode.next = tNode;
tNode.next=head; //delete this
}
}
As you can see, there are at least the following problems in your code:
tNode.next=head; is not necessary, since if you insert a node between pNode and tNode, tNode.next should not be affected (and if tNode is the last node, next should already point to the head, while in all other cases this assignment would be wrong).
In the two branches above, where you set head, you're not setting the next element of the last node to head. If you don't do this when adding the first node, that's not necessarily a problem, but leaving that out when adding a new head (second condition) you'll produce an incorrect state which then might result in endless loops
What you might want to do:
Remove the tNode.next=head; statement.
If you add a new head locate the last node and set the head as its next node. That means that if you have only one node, it references itself. If you add a node at the front (your second condition) you'll have to update the next reference of the last node, otherwise you'll get an endless loop if you try to add an element at the end.
After working two days on the code I finally solved it but this is not efficient code .
void insert(int e) {
Node nNode = new Node(); //the new node, step 1: A, step2: Z
Node tNode = head; //step1: points to B, step2: points to A
nNode.element = e;
if (head == null) { //false in both steps
head = nNode;
head.next = head;
}
else if (head.element > e) { //true in step 1, false in step 2
Node pNode = head;
pNode=tNode.next; //PNode is at head which will equal to tNode.next Which will be the next element
nNode.next = head;
head=nNode;
tNode.next.next=nNode; // Now I am moving the Tail Node next
} else {
Node pNode=head; //points to A because of step 1
while (tNode.next != head && tNode.element <= e) {
pNode = tNode;
tNode = tNode.next;
}
pNode.next = nNode;
nNode.next = tNode;
}
}
Hey I'm currently stuck on the reverse method of my DoublyLinkedList. Everything is working fine (somehow) except for the reverse method. I'm not receiving any errors - System.out.println(list.reverse()) simply has no output.
Any suggestions? Thank you very much in advance. :)
Okay: I have edited my code now. So far everyhing is working correctly. However, the recursive method simply prints the list in the same order, instead of actually reversing it.
Updated Code:
public class DoublyLinkedStringList {
private String content;
private DoublyLinkedStringList prev;
private DoublyLinkedStringList next;
public DoublyLinkedStringList(String info) {
content = info;
prev = null;
next = null;
}
private DoublyLinkedStringList(String content, DoublyLinkedStringList prev, DoublyLinkedStringList next) {
this.content = content;
this.prev = prev;
this.next = next;
}
public DoublyLinkedStringList prepend(String info) {
DoublyLinkedStringList newNode = new DoublyLinkedStringList(info);
prev = newNode;
newNode.next = this;
return newNode;
}
public DoublyLinkedStringList delete(int index) {
DoublyLinkedStringList curr = this;
if (index == 0) {
next.prev = null;
return next;
}
for (int i = 0; i < index; i++) {
curr = curr.next;
}
curr.prev.next = curr.next;
if (curr.prev.next != null) {
curr.prev.next.prev = curr.prev;
}
return this;
}
public DoublyLinkedStringList reverse() {
DoublyLinkedStringList currNode = this;
while (currNode != null) {
DoublyLinkedStringList temp = currNode.next;
currNode.next = currNode.prev;
currNode.prev = temp;
if (currNode.prev != null) {
currNode = currNode.prev;
}
}
return this;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (DoublyLinkedStringList currNode = this; currNode != null; currNode = currNode.next) {
sb.append(currNode.content);
if (currNode.next != null) {
sb.append(", ");
}
}
return sb.toString();
}
public static void main(String argv[]) {
DoublyLinkedStringList list = new DoublyLinkedStringList("Testliste");
list = list.prepend("6");
list = list.prepend("5");
list = list.prepend("4");
list = list.prepend("3");
list = list.prepend("2");
list = list.prepend("1");
list = list.prepend("0");
list = list.delete(1);
System.out.println(list);
list = list.reverse();
System.out.println(list);
}
}
One of the problems you are going to have with your design is when you reverse the list the head becomes the tail and the tail becomes the head. But the client is pointing to the head, and not the tail. Even if you did this operation 100% correct, you can't change the reference the client has. What you'll want to do is separate the concepts of the List as an object, and the Nodes that make up that object (currently you have combined these two concepts together because the nodes are the list and vice versa). By separating them the reference to the list is always the same regardless of what's in it, order, etc. The List contains the head and tail references, and the nodes only contain the next/prev. Right now you have head and tail in every node in your list which can make nasty bugs pop up if you don't replace every reference whenever head/tail changes (ie prepend, delete, or reverse). If you moved those two instances out of each node then you don't have to do as much maintenance to the list on changes. I think if you do that then you'll find it much easier to implement reverse.
Your error is exactly the problem I'm saying. At the end you return this, well the reference the client has was the head (ie this). However, after iterating over and reversing everything what was the head is now the tail so you've returned the new tail by returning this. And toString() on tail is NOTHING.
Normally I would implement the interface Iteratable and use an Iterator to reverse the list but I kept my revision in line with your current model. I changed the return types of the Node's getNext() and getPrev() methods to be dependent on the forward variable. Now the list never changes linkage when "reversed" but it is traversed in reverse order via the variable getNext() and getPrev() behavior.
IDEONE link to code
Consider this edit:
class DoublyLinkedStringList {
private Node head, tail;
boolean forward;
/**
* Diese Klasse repraesentiert einen Knoten in der Doubly Linked List der
* Klasse
* <code>DoublyLinkedStringList</code>
*
*/
private class Node {
private String content;
private Node next;
private Node prev;
public Node(String content) { this.content = content; }
public Node(String content, Node next) {
this.content = content;
if(forward) { this.next = next; } //EDITED
else { this.prev = next; } //EDITED
}
public Node getNext() { return (forward) ? next : prev; } //EDITED
public Node getPrev() { return (forward) ? prev : next; } //EDITED
public void setNext(Node next) {
if(forward) { this.next = next; } //EDITED
else { this.prev = next; } //EDITED
}
public void setPrev(Node prev) {
if(forward) { this.prev = prev; } //EDITED
else { this.next = prev; } //EDITED
}
}
public DoublyLinkedStringList() {
this.head = null;
this.tail = null;
}
public Node prepend(String info) {
Node newNode = new Node(info);
newNode.setPrev(null);
newNode.setNext(getHead());
if(newNode.getNext()!=null) {
newNode.getNext().setPrev(newNode); //EDITED
}
if(forward) { head = newNode; } //EDITED
else { tail = newNode; } //EDITED
if(getTail() == null) { //EDITED
if(forward) { tail = newNode; } //EDITED
else { head = newNode; } //EDITED
}
return head;
}
public Node delete(int index) {
Node currNode = getHead();
int count = 0;
if (index == 0) {
if(forward) { head = head.next; } //EDITED
else { tail = tail.prev; } //EDITED
return head;
}
while (currNode != null) {
if (count + 1 == index) {
currNode.next.prev = currNode.prev;
currNode.prev.next = currNode.next; //EDITED
break;
}
currNode = currNode.getNext(); //EDITED
count++;
}
return currNode;
}
private Node next() {
Node currNode = head;
if (forward) {
return currNode.getNext();
} else {
return currNode.getPrev();
}
}
public Node getHead() { return (forward) ? head : tail; } //EDITED
public Node getTail() { return (forward) ? tail : head; } //EDITED
public DoublyLinkedStringList reverse() { forward = !forward; return this; }
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
//EDITED LOOP STRUCTURE
for (Node currNode = getHead(); currNode != null; currNode = currNode.getNext()) {
sb.append(currNode.content);
if (currNode.getNext() != null) {
sb.append(", ");
}
}
return sb.toString();
}
public static void main(String argv[]) {
DoublyLinkedStringList list = new DoublyLinkedStringList();
list.prepend("6");
list.prepend("5");
list.prepend("4");
list.prepend("3");
list.prepend("2");
list.prepend("1");
list.prepend("0");
list.delete(3);
System.out.println(list);
System.out.println(list.reverse());
}
}
you simply have to set head and tail too. then it should work. but see chubbsondubs answer for further improvement!
Since you have a DoublyLinkedStringList as return type, I think you want to return a new object. In this case I suggest you to cycle over your object and build a new List using the prepend method you already implemented (that anycase has some other error). You can start with a empty list, and, as you scan the original object, prepend current element.
Otherwise, if you want to reverse the list "in place" you should return void, change the head with the last element, and, since is double linked, your should do anything else, since there are pointers to nodes in both directions.
try this for the reverse method:
public class DoublyLinkedList {
Node first, current;
boolean forward;
//constructors... methods...
private Node next() {
if(forward) return current.next();
else return current.previous();
}
public void reverse() {
while(true) {
if(next() == null) {
first = current;
forward = !forward;
return;
}
current = next();
}
}
}
Here is just my solution. I unfortunately do not have more time for explanatory notes.
public class DoublyLinkedStringList {
private String info;
private DoublyLinkedStringList prev;
private DoublyLinkedStringList next;
public DoublyLinkedStringList(String pInfo)
{
info = pInfo;
prev = null;
next = null;
}
private DoublyLinkedStringList(String pInfo, DoublyLinkedStringList pPrev, DoublyLinkedStringList pNext)
{
info = pInfo;
prev = pPrev;
next = pNext;
}
public DoublyLinkedStringList prepend(String info)
{
DoublyLinkedStringList n = new DoublyLinkedStringList(info);
prev = n;
n.next = this;
return n;
}
public DoublyLinkedStringList delete(int index)
{
if (index == 0)
{
next.prev = null;
return next;
}
DoublyLinkedStringList d = this;
for (int i = 0; i<index; i++)
d = d.next;
// d is now the node which should be deleted
// after delete(x) "next" schould be on pos x
d.prev.next = d.next; // take the next of the prev and set the new next to the next of d
if (d.prev.next != null) // if the next of d was not set to null, it must get to know his new prev (d's prev)
d.prev.next.prev = d.prev;
return this;
}
public DoublyLinkedStringList reverse() // moe or less less similar to my implementation in IntList.java
{
DoublyLinkedStringList oldLast = getLast();
next.reverse(this);
prev = next;
next = null;
return oldLast;
}
public void reverse(DoublyLinkedStringList last)
{
if (next != null)
next.reverse(this);
prev = next;
next = last;
}
public DoublyLinkedStringList getLast()
{
if (next == null)
return this;
return next.getLast();
}
#Override
public String toString()
{
String r = "";
for (DoublyLinkedStringList i = this; i != null; i = i.next)
{
r += i.info;
if (i.next != null)
r += ", ";
}
return r;
}
public String reverseToString() // uses prev; just for testing issues :)
{
String r = "";
for (DoublyLinkedStringList i = getLast(); i != null; i = i.prev)
{
r += i.info;
if (i.prev != null)
r += ", ";
}
return r;
}
public static void main(String argv[])
{
DoublyLinkedStringList list = new DoublyLinkedStringList("Test");
list = list.prepend("6");
list = list.prepend("5");
list = list.prepend("4");
list = list.prepend("3");
list = list.prepend("2");
list = list.prepend("1");
list = list.prepend("0");
list = list.delete(1);
System.out.println(list);
System.out.println(list.reverseToString()+"\n");
list = list.reverse();
System.out.println(list);
System.out.println(list.reverseToString());
list = list.delete(6);
list = list.delete(0);
System.out.println(list);
list = list.reverse();
list = list.prepend("1");
System.out.println(list);
}