package me.ramswaroop.common; import java.util.NoSuchElementException; import static java.lang.System.out; /** * Created by IntelliJ IDEA. * * @author: ramswaroop * @date: 6/16/15 * @time: 1:00 PM */ public class CircularSingleLinkedList<E extends Comparable<E>> implements LinkedList<E> { public SingleLinkedNode<E> head; public int size; @Override public boolean add(E item) { SingleLinkedNode<E> newNode = new SingleLinkedNode<>(item, head); if (head == null) { // list empty head = newNode; newNode.next = head; } else { // add to the end of list SingleLinkedNode<E> curr = head; while (curr.next != head) { curr = curr.next; } curr.next = newNode; } size++; return true; } @Override public boolean add(int index, E item) { isPositionIndex(index); if (index == 0) { // add at first addFirst(item); } else { // add at any other location SingleLinkedNode<E> nodeAtPrevIndex = getPredecessorNode(index); SingleLinkedNode<E> newNode = new SingleLinkedNode<>(item, nodeAtPrevIndex.next); nodeAtPrevIndex.next = newNode; size++; } return true; } @Override public void addFirst(E item) { SingleLinkedNode<E> newNode = new SingleLinkedNode<>(item, head), node; if (head == null) { // empty linked list newNode.next = newNode; } else { node = getNode(size - 1); node.next = newNode; } head = newNode; size++; } @Override public void addLast(E item) { add(item); } @Override public void clear() { // Clearing all of the links between nodes is "unnecessary", but: // - helps a generational GC if the discarded nodes inhabit // more than one generation // - is sure to free memory even if there is a reachable Iterator for (SingleLinkedNode<E> node = head; node != null; ) { SingleLinkedNode<E> next = node.next; node.item = null; node.next = null; node = next; } head = null; size = 0; } @Override public LinkedList<E> clone() { return null; } @Override public boolean contains(E item) { return getNode(item) != null; } @Override public E get(int index) { return getNode(index).item; } @Override public E getFirst() { isLinkedListEmpty(); return head.item; } @Override public E getLast() { return getNode(size - 1).item; } @Override public E remove() { isLinkedListEmpty(); E item = head.item; // last node should point to new head SingleLinkedNode<E> lastNode = getNode(size - 1); lastNode.next = head.next; head = (head.next != head) ? head.next : null; size--; return item; } @Override public E remove(int index) { isLinkedListEmpty(); SingleLinkedNode<E> prevNode = getPredecessorNode(index), delNode, lastNode; if (prevNode == null) { // index = 0 delNode = head; head = (head.next != head) ? head.next : null; size--; return delNode.item; } else { delNode = prevNode.next; prevNode.next = delNode.next; // last node should point to new head lastNode = getNode(size - 1); lastNode.next = head.next; head = head.next; size--; return delNode.item; } } @Override public boolean removeItem(E item) { isLinkedListEmpty(); if (!contains(item)) return false; SingleLinkedNode<E> prevNode = getPredecessorNode(item), lastNode; if (prevNode == null) { // index = 0 head = (head.next != head) ? head.next : null; size--; } else { prevNode.next = prevNode.next.next; // last node should point to new head lastNode = getNode(size - 1); lastNode.next = head.next; head = head.next; size--; } return true; } @Override public E set(int index, E item) { SingleLinkedNode<E> node = getNode(index); node.item = item; return node.item; } @Override public int size() { return size; } @Override public void printList() { printList(head); } public void printList(SingleLinkedNode<E> node) { SingleLinkedNode<E> curr = node; out.print("["); if (curr == null) { out.println("]"); return; } while (curr.next != head) { out.print(curr.item + ","); curr = curr.next; } out.println(curr.item + "]"); } public static <E extends Comparable<E>> CircularSingleLinkedList<E> getLinkedList(SingleLinkedNode<E> node) { CircularSingleLinkedList<E> linkedList = new CircularSingleLinkedList<>(); // set head linkedList.head = node; // set size SingleLinkedNode<E> curr = node; while (curr != linkedList.head) { linkedList.size++; curr = curr.next; } return linkedList; } private SingleLinkedNode<E> getPredecessorNode(int index) { return index > 0 ? getNode(index - 1) : null; } private SingleLinkedNode<E> getPredecessorNode(E item) { SingleLinkedNode<E> prev = null; SingleLinkedNode<E> curr = head; if (item == null) { while (curr != head) { if (curr.item == item) { // when item is null, use == rather than equals() return prev; } prev = curr; curr = curr.next; } } else { while (curr != head) { if (curr.item.equals(item)) { return prev; } prev = curr; curr = curr.next; } } return null; } public SingleLinkedNode<E> getNode(int index) { isElementIndex(index); SingleLinkedNode<E> curr = head; int i = 0; while (i < index) { curr = curr.next; i++; } return curr; } public SingleLinkedNode<E> getNode(E item) { SingleLinkedNode<E> curr = head; if (item == null) { while (curr != head) { // when item is null, use == rather than equals() if (curr.item == item) { return curr; } curr = curr.next; } } else { while (curr != head) { if (curr.item.equals(item)) { return curr; } curr = curr.next; } } return null; } private void isLinkedListEmpty() { if (head == null) { throw new NoSuchElementException("LinkedList empty"); } } /** * Tells if the argument is the index of an existing element. */ private void isElementIndex(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("Index [" + index + "] must be less than size [" + size + "]"); } } /** * Tells if the argument is the index of a valid position for an * iterator or an add operation. */ private void isPositionIndex(int index) { if (index < 0 || index > size) { throw new IndexOutOfBoundsException("Index [" + index + "] must be less than or equal to size [" + size + "]"); } } }