package DataStructures.Lists; /** * This class implements a DoublyLinkedList. This is done using the classes LinkedList and Link. * *

A linked list is similar to an array, it holds values. However, links in a linked list do not * have indexes. With a linked list you do not need to predetermine it's size as it grows and * shrinks as it is edited. This is an example of a double ended, doubly linked list. Each link * references the next link and the previous one. * * @author Unknown */ public class DoublyLinkedList { /** Head refers to the front of the list */ private Link head; /** Tail refers to the back of the list */ private Link tail; /** Size refers to the number of elements present in the list */ private int size; /** Default Constructor */ public DoublyLinkedList() { head = null; tail = null; size = 0; } /** * Constructs a list containing the elements of the array * * @param array the array whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public DoublyLinkedList(int[] array) { if (array == null) throw new NullPointerException(); for (int i : array) { insertTail(i); } size = array.length; } /** * Insert an element at the head * * @param x Element to be inserted */ public void insertHead(int x) { Link newLink = new Link(x); // Create a new link with a value attached to it if (isEmpty()) // Set the first element added to be the tail tail = newLink; else head.previous = newLink; // newLink <-- currenthead(head) newLink.next = head; // newLink <--> currenthead(head) head = newLink; // newLink(head) <--> oldhead ++size; } /** * Insert an element at the tail * * @param x Element to be inserted */ public void insertTail(int x) { Link newLink = new Link(x); newLink.next = null; // currentTail(tail) newlink --> if (isEmpty()) { // Check if there are no elements in list then it adds first element tail = newLink; head = tail; } else { tail.next = newLink; // currentTail(tail) --> newLink --> newLink.previous = tail; // currentTail(tail) <--> newLink --> tail = newLink; // oldTail <--> newLink(tail) --> } ++size; } /** * Insert an element at the index * * @param x Element to be inserted * @param index Index(from start) at which the element x to be inserted */ public void insertElementByIndex(int x, int index) { if (index > size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); if (index == 0) { insertHead(x); } else { if (index == size) { insertTail(x); } else { Link newLink = new Link(x); Link previousLink = head; // for (int i = 1; i < index; i++) { // Loop to reach the index previousLink = previousLink.next; } // previousLink is the Link at index - 1 from start previousLink.next.previous = newLink; newLink.next = previousLink.next; newLink.previous = previousLink; previousLink.next = newLink; } } ++size; } /** * Delete the element at the head * * @return The new head */ public Link deleteHead() { Link temp = head; head = head.next; // oldHead <--> 2ndElement(head) if (head == null) { tail = null; } else { head.previous = null; // oldHead --> 2ndElement(head) nothing pointing at old head so will be removed } --size; return temp; } /** * Delete the element at the tail * * @return The new tail */ public Link deleteTail() { Link temp = tail; tail = tail.previous; // 2ndLast(tail) <--> oldTail --> null if (tail == null) { head = null; } else { tail.next = null; // 2ndLast(tail) --> null } --size; return temp; } /** * Delete the element from somewhere in the list * * @param x element to be deleted * @return Link deleted */ public void delete(int x) { Link current = head; while (current.value != x) { // Find the position to delete if (current != tail) { current = current.next; } else { // If we reach the tail and the element is still not found throw new RuntimeException("The element to be deleted does not exist!"); } } if (current == head) deleteHead(); else if (current == tail) deleteTail(); else { // Before: 1 <--> 2(current) <--> 3 current.previous.next = current.next; // 1 --> 3 current.next.previous = current.previous; // 1 <--> 3 } --size; } /** * Inserts element and reorders * * @param x Element to be added */ public void insertOrdered(int x) { Link newLink = new Link(x); Link current = head; while (current != null && x > current.value) // Find the position to insert current = current.next; if (current == head) insertHead(x); else if (current == null) insertTail(x); else { // Before: 1 <--> 2(current) <--> 3 newLink.previous = current.previous; // 1 <-- newLink current.previous.next = newLink; // 1 <--> newLink newLink.next = current; // 1 <--> newLink --> 2(current) <--> 3 current.previous = newLink; // 1 <--> newLink <--> 2(current) <--> 3 } ++size; } /** * Deletes the passed node from the current list * * @param z Element to be deleted */ public void deleteNode(Link z) { if (z.next == null) { deleteTail(); } else if (z == head) { deleteHead(); } else { // before <-- 1 <--> 2(z) <--> 3 --> z.previous.next = z.next; // 1 --> 3 z.next.previous = z.previous; // 1 <--> 3 } --size; } public static void removeDuplicates(DoublyLinkedList l) { Link linkOne = l.head; while (linkOne.next != null) { // list is present Link linkTwo = linkOne.next; // second link for comparison while (linkTwo.next != null) { if (linkOne.value == linkTwo.value) // if there are duplicates values then l.delete(linkTwo.value); // delete the link linkTwo = linkTwo.next; // go to next link } linkOne = linkOne.next; // go to link link to iterate the whole list again } } /** Clears List */ public void clearList() { head = null; tail = null; size = 0; } /** * Returns true if list is empty * * @return true if list is empty */ public boolean isEmpty() { return (head == null); } /** Prints contents of the list */ public void display() { // Prints contents of the list Link current = head; while (current != null) { current.displayLink(); current = current.next; } System.out.println(); } } /** * This class is used to implement the nodes of the linked list. * * @author Unknown */ class Link { /** Value of node */ public int value; /** This points to the link in front of the new link */ public Link next; /** This points to the link behind the new link */ public Link previous; /** * Constructor * * @param value Value of node */ public Link(int value) { this.value = value; } /** Displays the node */ public void displayLink() { System.out.print(value + " "); } /** * Main Method * * @param args Command line arguments */ public static void main(String args[]) { DoublyLinkedList myList = new DoublyLinkedList(); myList.insertHead(13); myList.insertHead(7); myList.insertHead(10); myList.display(); // <-- 10(head) <--> 7 <--> 13(tail) --> myList.insertTail(11); myList.display(); // <-- 10(head) <--> 7 <--> 13 <--> 11(tail) --> myList.deleteTail(); myList.display(); // <-- 10(head) <--> 7 <--> 13(tail) --> myList.delete(7); myList.display(); // <-- 10(head) <--> 13(tail) --> myList.insertOrdered(23); myList.insertOrdered(67); myList.insertOrdered(3); myList.display(); // <-- 3(head) <--> 10 <--> 13 <--> 23 <--> 67(tail) --> myList.insertElementByIndex(5, 1); myList.display(); // <-- 3(head) <--> 5 <--> 10 <--> 13 <--> 23 <--> 67(tail) --> myList.clearList(); myList.display(); myList.insertHead(20); myList.display(); } }