I am trying to implement Knuth's Dancing Links algorithm in Java.
According to Knuth, if x is a node, I can totally unlink a node by the following operations in C:
L[R[x]]<-L[x]
R[L[x]]<-R[x]
And revert the unlinking by:
L[R[x]]<-x
R[L[x]]<-x
What am I doing wrongly in my main method?
How do you implement the unlinking and revert in Java?
Here's my main method:
///////////////
DoublyLinkedList newList = new DoublyLinkedList();
for (int i = 0; i < 81; i++) {
HashSet<Integer> set = new HashSet<Integer>();
set.add(i);
newList.addFirst(set);
}
newList.displayList();
// start at 69
newList.getAt(12).displayNode();
//HOW TO IMPLEMENT UNLINK?
//newList.getAt(12).previous() = newList.getAt(12).next().previous().previous();
//newList.getAt(12).next() = newList.getAt(12).previous().next().next();
newList.displayList();
//HOW TO IMPLEMENT REVERT UNLINK?
//newList.getAt(12) = newList.getAt(12).next().previous();
//newList.getAt(12) = newList.getAt(12).previous().next();
System.out.println();
///////////////
Here's the DoublyLinkedList class:
public class DoublyLinkedList<T> {
public Node<T> first = null;
public Node<T> last = null;
static class Node<T> {
private T data;
private Node<T> next;
private Node<T> prev;
public Node(T data) {
this.data = data;
}
public Node<T> get() {
return this;
}
public Node<T> set(Node<T> node) {
return node;
}
public Node<T> next() {
return next;
}
public Node<T> previous() {
return prev;
}
public void displayNode() {
System.out.print(data + " ");
}
#Override
public String toString() {
return data.toString();
}
}
public void addFirst(T data) {
Node<T> newNode = new Node<T>(data);
if (isEmpty()) {
newNode.next = null;
newNode.prev = null;
first = newNode;
last = newNode;
} else {
first.prev = newNode;
newNode.next = first;
newNode.prev = null;
first = newNode;
}
}
public Node<T> getAt(int index) {
Node<T> current = first;
int i = 1;
while (i < index) {
current = current.next;
i++;
}
return current;
}
public boolean isEmpty() {
return (first == null);
}
public void displayList() {
Node<T> current = first;
while (current != null) {
current.displayNode();
current = current.next;
}
System.out.println();
}
public void removeFirst() {
if (!isEmpty()) {
Node<T> temp = first;
if (first.next == null) {
first = null;
last = null;
} else {
first = first.next;
first.prev = null;
}
System.out.println(temp.toString() + " is popped from the list");
}
}
public void removeLast() {
Node<T> temp = last;
if (!isEmpty()) {
if (first.next == null) {
first = null;
last = null;
} else {
last = last.prev;
last.next = null;
}
}
System.out.println(temp.toString() + " is popped from the list");
}
}
I am not familiar with Knuth's Dancing Links algorithm, but found this article which made it quiet clear. In particular I found this very helpful:
Knuth takes advantage of a basic principle of doubly-linked lists.
When removing an object from a list, only two operations are needed:
x.getRight().setLeft( x.getLeft() )
x.getLeft().setRight(> x.getRight() )
However, when putting the object back in the list, all
is needed is to do the reverse of the operation.
x.getRight().setLeft( x )
x.getLeft().setRight( x )
All that is
needed to put the object back is the object itself, because the object
still points to elements within the list. Unless x’s pointers are
changed, this operation is very simple.
To implement it I added setters for linking / unlinking. See comments:
import java.util.HashSet;
public class DoublyLinkedList<T> {
public Node<T> first = null;
public Node<T> last = null;
static class Node<T> {
private T data;
private Node<T> next;
private Node<T> prev;
public Node(T data) {
this.data = data;
}
public Node<T> get() {
return this;
}
public Node<T> set(Node<T> node) {
return node;
}
public Node<T> next() {
return next;
}
//add a setter
public void setNext(Node<T> node) {
next = node;
}
public Node<T> previous() {
return prev;
}
//add a setter
public void setPrevious(Node<T> node) {
prev = node;
}
public void displayNode() {
System.out.print(data + " ");
}
#Override
public String toString() {
return data.toString();
}
}
public void addFirst(T data) {
Node<T> newNode = new Node<T>(data);
if (isEmpty()) {
newNode.next = null;
newNode.prev = null;
first = newNode;
last = newNode;
} else {
first.prev = newNode;
newNode.next = first;
newNode.prev = null;
first = newNode;
}
}
public Node<T> getAt(int index) {
Node<T> current = first;
int i = 1;
while (i < index) {
current = current.next;
i++;
}
return current;
}
public boolean isEmpty() {
return (first == null);
}
public void displayList() {
Node<T> current = first;
while (current != null) {
current.displayNode();
current = current.next;
}
System.out.println();
}
public void removeFirst() {
if (!isEmpty()) {
Node<T> temp = first;
if (first.next == null) {
first = null;
last = null;
} else {
first = first.next;
first.prev = null;
}
System.out.println(temp.toString() + " is popped from the list");
}
}
public void removeLast() {
Node<T> temp = last;
if (!isEmpty()) {
if (first.next == null) {
first = null;
last = null;
} else {
last = last.prev;
last.next = null;
}
}
System.out.println(temp.toString() + " is popped from the list");
}
public static void main(String[] args) {
///////////////
DoublyLinkedList newList = new DoublyLinkedList();
for (int i = 0; i < 81; i++) {
HashSet<Integer> set = new HashSet<Integer>();
set.add(i);
newList.addFirst(set);
}
newList.displayList();
// start at 69
Node node = newList.getAt(12);
node.displayNode(); System.out.println();
//HOW TO IMPLEMENT UNLINK?
node.previous().setNext(node.next);
node.next().setPrevious(node.previous());
//The 2 statements above are equivalent to
//Node p = node.previous();
//Node n = node.next();
//p.setNext(n);
//n.setPrevious(p);
newList.displayList();
//HOW TO IMPLEMENT REVERT UNLINK?
node.previous().setNext(node);
node.next().setPrevious(node);
newList.displayList(); System.out.println();
///////////////
}
}
Related
I have been debugging this for hours and I cannot see any reason why my search method cannot find anything. and my toString only ever returns the first node, then again, nothing. can someone help me?
While debugging, I can confirm that the order of the list is correct, I can switch around the addLast and addFirst and will always return what should be the first element, but otherwise, I do not know. the first is always sored in head.info and during debugging I see that but then the prev and next are still null.
thanks in advance!
public class DoubleLinkedList {
private DoubleNode head;
public DoubleLinkedList() {
head = null;
}
public class DoubleNode {
int info;
DoubleNode prev;
DoubleNode next;
public DoubleNode(int key) {
info = key;
prev = next = null;
}
}
public DoubleNode search(int key) {
DoubleNode current = this.head;
while (current != null && current.info != key) {
current = current.next;
}
return current;
}
public void addFirst(int key) {
this.head = new DoubleNode(key);
}
public void addLast(int key) {
DoubleNode node = new DoubleNode(key);
DoubleNode current;
if (head == null) {
this.head = node;
} else {
current = this.head;
while (current.next != null) {
current = current.next;
current.next = node;
node.prev = current;
}
}
}
public int delete(int key) {
DoubleNode current, sent;
current = search( key );
if (current != null) {
sent = delete( current );
return sent.info;
} else {
return -1;
}
}
private DoubleNode delete(DoubleNode node) {
if (node.prev != null) {
(node.prev).next = node.next;
} else {
this.head = node.next;
}
if (node.next != null) {
(node.next).prev = node.prev;
}
return node;
}
public String toString() {
String string = "";
while (head != null) {
string += head.info + " ";
head = head.next;
}
return string;
}
public static void main(String[] args) {
DoubleLinkedList test = new DoubleLinkedList();
test.addLast( 3 );
test.addLast( 5 );
test.addFirst( 7 );
System.out.println(test);
System.out.println( "Search: " + test.search( 1 ) );
}
}
The results come out as:
7,
Search: null
Your addFirst method isn't currently setting the new head's next property. It needs to be something more like this:
public void addFirst(int key) {
DoubleNode node = new DoubleNode(key);
node.next = this.head;
this.head = node;
}
Take a look at this example:
public class Test {
public static void main(String[] args) {
List list = new List();
list.addNode("1");
list.addNode("2");
list.addNode("3");
System.out.println(list);// not implemented
}
}
class List {
Node head;
Node tail;
class Node {
Node next;
Node previous;
String info;
public Node(String info) {
this.info = info;
}
}
void addNode(String info) {
Node node = new Node(info);
if (head == null) {
head = tail = node;
} else if(tail == head){
Node next = new Node(info);
tail.next = next;
head = next;
head.previous = tail;
} else{
Node next = new Node(info);
Node current = head;
head.next =next;
head = next;
head.previous = current;
}
}
}
I've created a sorted linked list class, and the only part I'm struggling with is implementing the toArray() method properly.
public class SortedLinkedList<T extends Comparable<T>> implements ListInterface<T>
{
// container class
private class LinkedNode<T>
{
public T data;
public LinkedNode<T> next;
public LinkedNode(T data, LinkedNode<T> next)
{
this.data = data;
this.next = next;
}
}
// private variables
private LinkedNode<T> head, tail;
private int size;
private String name;
// constructor
public SortedLinkedList(String name)
{
head = null;
tail = null;
size = 0;
this.name = name;
}
// core functions
public void Add(T data)
{
size++;
// creation of new node to be added
LinkedNode<T> newNode = new LinkedNode<T>(data, null);
// check for empty list; adds node at head if so
if (head == null)
{
head = newNode;
return;
}
if (head.data.compareTo(data) < 0)
{
head = newNode;
return;
}
// insertion in middle
LinkedNode<T> current = head;
LinkedNode<T> prev = null;
while (current != null)
{
if (current.data.compareTo(data) > 0)
{
prev.next = newNode;
newNode.next = current;
return;
}
prev = current;
current = current.next;
}
// insertion at end
prev.next = newNode;
return;
}
public void Remove(T data)
{
if (head == null)
{
return;
}
LinkedNode<T> current = head.next;
while (current != null && current.next != null)
{
if (current.data.compareTo(current.next.data) == 0)
{
current.next = current.next.next;
} else {
current = current.next;
}
}
size--;
}
public int size()
{
return size;
}
#SuppressWarnings("unchecked")
public T[] toArray()
{
T[] result = (T[])(new Comparable[size()]);
int counter = 0;
for ( T item : )
{
result[counter++] = item;
}
return result;
}
The problem I'm having is what I should include after "T item : " in my for/each line. I had no problem with implementing a similar toArray() method in a set class recently, as that was "for each item in the set", but for some reason I'm blanking on what to place there for the linked list.
Try this.
#SuppressWarnings("unchecked")
public T[] toArray()
{
T[] result = (T[])(new Comparable[size()]);
int counter = 0;
for ( LinkedNode<T> cursor = head; cursor != null; cursor = cursor.next )
{
result[counter++] = cursor.data;
}
return result;
}
Actually, the answer to your question is this:
#SuppressWarnings("unchecked")
public T[] toArray() {
T[] result = (T[])(new Comparable[size()]);
int counter = 0;
for (T item : this) {
result[counter++] = item;
}
return result;
}
This is correct, but to do this you have to implement Iterable<T> interface:
public class SortedLinkedList<T extends Comparable<T>> implements ListInterface<T>, Iterable<T> {
#Override
public Iterator<T> iterator() {
return null;
}
// ...
}
Don't use for loop with linked-lists. Try something like below:
LinkedNode cursor = head;
int index = 0;
while (cursor != null ){
result[index] = cursor.data;
cursor = cursor.next;
index++;
}
I am currently trying to understand Singly linked lists.
I don't understand some of the code in the SinglyLinkedList.java class. How can the Node class be called and then assigned like: private Node first;
I would have thought that you would have to do something like this
Node<T> help =new Node<>();
help = first;
If someone could explain, or provide me to a link that would help me, it would be much appreciated.
Thanks!
public class Node<T> {
public T elem;
public Node<T> next;
public Node(T elem) {
this.elem = elem;
next = null;
}
public Node(T elem, Node<T> next) {
this.elem = elem;
this.next = next;
}
#Override
public String toString() {
return "Node{" + "elem=" + elem + '}';
}
}
package list;
/**
*
* #author dcarr
*/
public class SinglyLinkedList<T> implements List<T> {
private Node<T> first;
private Node<T> last;
public SinglyLinkedList() {
first = null;
last = null;
}
#Override
public boolean isEmpty() {
return first == null;
}
#Override
public int size() {
if (isEmpty()){
return 0;
} else {
int size = 1;
Node<T> current = first;
while(current.next != null){
current = current.next;
size++;
}
return size;
}
}
#Override
public T first() {
return first.elem;
}
#Override
public void insert(T elem) {
// if there is nothing in the list
if (isEmpty()){
first = new Node<>(elem);
last = first;
// if the list has elements already
} else {
// the new element will be the next of what was the last element
last.next = new Node<>(elem);
last = last.next;
}
}
#Override
public void remove(T elem) {
if (!isEmpty()){
int index = 0;
Node<T> current = first;
while (current != null && current.elem != elem){
current= current.next;
index++;
}
remove(index);
}
}
#Override
public String toString() {
if (isEmpty()){
return "Empty List";
} else {
String str = first.elem.toString() + " ";
Node<T> current = first;
while(current.next != null){
current = current.next;
str += current.elem.toString() + " ";
}
return str;
}
}
#Override
public void insertAt(int index, T e) {
if (index == 0){
first = new Node<>(e, first);
if (last == null){
last = first;
}
return;
}
Node<T> pred = first;
for (int i = 0; i < index-1; i++) {
pred = pred.next;
}
pred.next = new Node<>(e, pred.next);
System.out.println(pred);
if (pred.next.next == null){
// what does this mean pred.next is?
last = pred.next;
}
}
#Override
public void remove(int index) {
if (index < 0 || index >= size()){
throw new IndexOutOfBoundsException();
} else if (isEmpty()){
return;
}
if (index == 0){
first = first.next;
if (first == null){
last = null;
}
return;
}
Node<T> pred = first;
for (int i = 1; i <= index-1; i++) {
pred = pred.next;
}
// remove pred.next
pred.next = pred.next.next;
if (pred.next == null){
last = pred;
}
}
}
The first field is automatically initialized to null:
private Node<T> first;
I assume there will be some method to add an element at the end like so:
public void add(T element) {
if (first == null) {
first = new Node<T>(element);
last = first;
}
else {
last.next = new Node<>(element);
last = last.next;
}
}
So when you create a new SinglyLinkedList:
SinglyLinkedList<String> sillyList = new SinglyLinkedList<>();
The first and last fields both hold a null reference.
Note that the first method will cause a NullPointerException at this point. A better implementation would be:
#Override
public Optional<T> first() {
if (first != null) {
return Optional.ofNullable(first.elem);
}
else {
return Optional.empty();
}
}
Now if you add an element:
sillyList.add("Adam");
The code executed in the add method is:
first = new Node<>(elem);
last = first;
So first points to a new Node instance with an elem field holding the value "Adam". And last points to that same Node instance.
Some of the methods in this class I would implement differently, for example:
#Override
public void remove(int index) {
if (index < 0) {
throw new IndexOutOfBoundsException("Index cannot be negative");
}
else if (index == 0 && first != null) {
first = null;
last = null;
}
else {
Node<T> curr = new Node<>("dummy", first);
int c = 0;
while (curr.next != null) {
if (c == index) {
curr.next = curr.next.next;
if (curr.next == null) {
last = curr;
}
return;
}
curr = curr.next;
c++;
}
throw new IndexOutOfBoundsException(String.valueOf(c));
}
Also, some of the methods don't actually exist in the java.util.List interface, like insert, insertAt and first. So these methods must not have the #Override annotation.
public class Node<E> {
private E element;
public Node<E> next;
int data;
Node(int d)
{
data = d;
next = null;
}
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> n) {
next = n;
}
public void displayNode(){
System.out.print(element+ " ");
}
}
public class SinglyLinkedList<E> {
private Node<E> head;
private Node<E> tail;
private int size;
public SinglyLinkedList() {
head = tail = null;
size = 0;
}
public SinglyLinkedList(Node<E> head, Node<E> tail) {
this.head = head;
this.tail = tail;
}
public Node<E> getHead() {
return head;
}
public Node<E> getTail() {
return tail;
}
public void setHead(Node<E> head) {
this.head = head;
}
public void setTail(Node<E> tail) {
this.tail = tail;
}
public boolean isEmpty() {
if (head == null) {
return true;
}
return false;
}
public E first() {
return head.getElement();
}
public E last() {
return tail.getElement();
}
public void addFirst(E e) {
if (head == null) {
head = tail = new Node(e, null);
} else {
Node<E> newest = new Node(e, head);
head = newest;
}
size++;
}
public void addLast(E e) {
if (tail == null) {
head = tail = new Node(e, null);
} else {
Node<E> newest = new Node(e, null);
tail.setNext(newest);
tail = newest;
}
size++;
}
public E removeFirst() {
E e = head.getElement();
head = head.getNext();
size--;
return e;
}
#Override
public String toString() {
Node<E> tmp = head;
String s = "";
while (tmp != null) {
s += tmp.getElement();
tmp=tmp.getNext();
}
return s;
}
public void displayList() {
Node current = head;
while (current != null) {
current.displayNode();
current = current.next;
}
}
}
public interface Queue<E> {
int size();
boolean isEmpty();
void enqueue( );
E first();
E dequeue();
}
public class LinkedQueue<E> implements Queue<E> {
private SinglyLinkedList<E> list = new SinglyLinkedList<>();
public LinkedQueue() {
}
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public void enqueue(E element) {
list.addLast(element);
}
public E first() {
return list.first();
}
public E dequeue() {
return list.removeFirst();
}
#Override
public void enqueue() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools |list.addLast(element);
}
public void displayQueue() {
list.displayList();
System.out.println();
}
public class Main {
public static void main(String[] args) {
LinkedQueue list = new LinkedQueue();
list.enqueue(sam);
list.enqueue(adams);
list.enqueue(john);
list.enqueue(isac);
list.enqueue(gad);
System.out.print("\n Linked list before calling swapNodes() ");
list.displayQueue();
}}
How to change the order of these names in the queue?
I have try to put function that swap nodes in the singlylinkedlist class but it didn't work.i m confused in which layer should i make this function in the linkedqueue class or the singlylinkedlist class or in the main class. yes i want just to swap names in the queue as simple as that.
UPDATED ANSWER
I modified your Node and NodeList Classes in a way which is easier to understand. I also kept similar private values and similar methods for those classes.
public class JavaApplication287 {
public static class Node{
private Node node;
private Node nextNode;
int data;
Node(int d){
data = d;
nextNode = null;
}
public Node getNode(){return node;}
public void setNode(Node someNode){node = someNode;}
public Node getNextNode(){return nextNode;}
public void setNextNode(Node someNextNode){nextNode = someNextNode;}
public int getData(){return data;}
public void setData(int d){data = d;}
public void printNode(){System.out.println(data);}
}
public static class NodeLinkedList{
private Node head;
private Node tail;
private int size;
NodeLinkedList(Node nodeHead, Node nodeTail, int s){
this.head = nodeHead;
this.tail = nodeTail;
this.size = s;
}
public Node getHead(){return head;}
public void setHead(Node n){head = n;}
public Node getTail(){return tail;}
public void setTail(Node n){tail = n;}
public int getSize(){return size;}
public void setSize(int n){size = n;}
public void printNodeList(){
System.out.println("Head: " + head.getData());
Node current = head;
while (current.nextNode != null){
System.out.println(current.data);
current = current.getNextNode();
}
System.out.println("Tail: " + tail.getData());
}
}
public static void main(String[] args) {
// create Sample Nodes
Node zero = new Node(0);
Node one = new Node(1);
Node two = new Node(2);
Node three = new Node(3);
Node four = new Node(4);
Node five = new Node(5);
//Link Them
zero.setNextNode(one);
one.setNextNode(two);
two.setNextNode(three);
three.setNextNode(four);
four.setNextNode(five);
//Create the Linked Node List with head = one & tail = five
NodeLinkedList myNodeLinkedList = new NodeLinkedList(zero, five, 6);
//Print Current LinkedNodes
myNodeLinkedList.printNodeList();
//Invert the NodeLinkedList
Node position = myNodeLinkedList.getHead(); //Node we look at
Node prev = null; // Store the prev Node
Node node = null; // Temp Node of the next Node in the Linked List
for (int i=0; i< myNodeLinkedList.getSize(); i++){
node = position.getNextNode(); //Store the Next Node so we do not lose access to it
position.setNextNode(prev); // Update current Node's NextNode value
prev = position; // Set previous Node as the Node we are currently looking at
position = node; // Move our position to the next Node
}
//Invert Head and Tail
Node temp = myNodeLinkedList.getHead();
myNodeLinkedList.setHead(myNodeLinkedList.getTail());
myNodeLinkedList.setTail(temp);
//Print Current LinkedNodes
myNodeLinkedList.printNodeList();
}
}
This is working code and here is the output I get,
run:
Head: 0
0
1
2
3
4
Tail: 5
Head: 5
5
4
3
2
1
Tail: 0
BUILD SUCCESSFUL (total time: 0 seconds)
Hope it helps,
I'm really struggling to fix my code for this. I've created a Doubly Linked list that I am trying to traverse in reverse.
Any ideas?
Here's my code: Node.java:
public class Node {
String data;
Node next;
public Node(String data) {
super();
this.data = data;
this.next = null;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public Node getNext() {
if (this.next != null)
return this.next;
else
return null;
}
public void setNext(Node a) {
this.next = a;
}
#Override
public String toString() { //CHECK
if(data== null){
return "null";
}
else
return data + "-->";
}
}
Here's the second class "DNode.java":
public class DNode extends Node {
Node prev;
public DNode(String data) {
super(data);
this.prev = null;
}
public Node getPrev() {
return prev;
}
public void setPrev(Node prev) {
this.prev = prev;
}
}
Lastly, here is DoublyLinkedList.java: (Overrides "add" and "remove" methods from another class "Linked List")
public class DoublyLinkedList extends LinkedList {
DNode head, tail,current;
public DoublyLinkedList() {
this.head = this.tail = this.current = null;
}
public void add(DNode a) { //CHECK
if (this.head == null) {
this.head = tail = current= a;
this.head.prev = null;
}
else{
//a.setPrev(this.current);
this.current.next= a;
a.setPrev(this.current);
this.current = this.tail = a;
}
}
#Override
public void remove(String removestring) {
this.current = head;
this.current.prev = head;
while (this.current.getData() != removestring) {
if (this.current.next == null) {
System.out.println("not found");
return;
} else {
this.current.prev = this.current;
this.current = (DNode) current.next;
}
}
if (this.current == head) {
head = (DNode) head.next;
} else {
this.current.prev.next = (DNode) this.current.next;
}
}
public void printList() {
DNode temp = this.head;
while (temp != null) {
System.out.println(temp);
temp = (DNode) temp.getNext();
}
}
public void reverseList(){
this.current = this.tail;
this.current.setNext(this.current.getPrev());
this.current.setPrev(null);
this.current = (DNode) this.current.getNext();
while(this.current.getPrev()!= null){
if(this.current.getNext() == null){
this.current.setNext((this.current).getPrev());
this.current.setPrev(null);
this.current = (DNode)this.current.getNext();
}
else{
DNode tempprev = (DNode) this.current.getNext();
this.current.setNext(this.current.getPrev());
this.current.setPrev(tempprev);
this.current = (DNode) this.current.getNext();
}
DNode temp2 = this.tail;
this.head = this.tail;
this.tail = temp2;
}
}
I'm able to print the list going forwards, but going backwards I am running into an infinite loop. Any ideas?
Thanks!
Well, we already have a method to go forwards. Because this is doubly linked, we can just convert this code line by line and instead of moving next (forwards) we move previous (backwards). We also start at the tail instead of the head.
Whereas this was your old method for printing forwards:
public void printList() {
DNode temp = this.head;
while (temp != null) {
System.out.println(temp);
temp = (DNode) temp.getNext();
}
}
This could be your new method for printing backwards:
public void printBackwardsList() {
DNode temp = this.tail;
while(temp != null) {
System.out.println(temp);
temp = (DNode) temp.getPrev();
}
}
Notice how they are almost exactly the same, except we swapped out tail for head and getNext for getPrev.
Your class model seems overly complex. You don't need a DNode class at all to do this. Your method to print the list in reverse should be as simple as the method to print the list normally
public void printListReverse() {
Node temp = this.tail;
while (temp != null) {
System.out.println(temp);
temp = temp.getPrevious();
}
}
assuming you build and maintain the list properly.
while(this.current.getPrev()!= null)
replace with
while(this.current.getPrev()!= head)