package com.jwetherell.algorithms.data_structures; import java.util.Arrays; import com.jwetherell.algorithms.data_structures.interfaces.IList; @SuppressWarnings("unchecked") public abstract class List implements IList { /** * A dynamic array, growable array, resizable array, dynamic table, or array * list is a random access, variable-size list data structure that allows * elements to be added or removed. * * http://en.wikipedia.org/wiki/Dynamic_array * * @author Justin Wetherell */ public static class ArrayList extends List { private static final int MINIMUM_SIZE = 1024; private int size = 0; private T[] array = (T[]) new Object[MINIMUM_SIZE]; /** * {@inheritDoc} */ @Override public boolean add(T value) { return add(size,value); } /** * Add value to list at index. * * @param index to add value. * @param value to add to list. */ public boolean add(int index, T value) { if (size >= array.length) grow(); if (index==size) { array[size] = value; } else { // Shift the array down one spot System.arraycopy(array, index, array, index+1, size - index); array[index] = value; } size++; return true; } /** * {@inheritDoc} */ @Override public boolean remove(T value) { for (int i = 0; i < size; i++) { T obj = array[i]; if (obj.equals(value)) { if (remove(i)!=null) return true; return false; } } return false; } /** * Remove value at index from list. * * @param index of value to remove. * @return value at index. */ public T remove(int index) { if (index<0 || index>=size) return null; T t = array[index]; if (index != --size) { // Shift the array down one spot System.arraycopy(array, index + 1, array, index, size - index); } array[size] = null; int shrinkSize = array.length>>1; if (shrinkSize >= MINIMUM_SIZE && size < shrinkSize) shrink(); return t; } // Grow the array by 50% private void grow() { int growSize = size + (size<<1); array = Arrays.copyOf(array, growSize); } // Shrink the array by 50% private void shrink() { int shrinkSize = array.length>>1; array = Arrays.copyOf(array, shrinkSize); } /** * Set value at index. * * @param index of value to set. * @param value to set. * @return value previously at index. */ public T set(int index, T value) { if (index<0 || index>=size) return null; T t = array[index]; array[index] = value; return t; } /** * Get value at index. * * @param index of value to get. * @return value at index. */ public T get(int index) { if (index<0 || index>=size) return null; return array[index]; } /** * {@inheritDoc} */ @Override public void clear() { size = 0; } /** * {@inheritDoc} */ @Override public boolean contains(T value) { for (int i = 0; i < size; i++) { T obj = array[i]; if (obj.equals(value)) return true; } return false; } /** * {@inheritDoc} */ @Override public int size() { return size; } /** * {@inheritDoc} */ @Override public boolean validate() { int localSize = 0; for (int i=0; i toList() { return (new JavaCompatibleArrayList(this)); } /** * {@inheritDoc} */ @Override public java.util.Collection toCollection() { return (new JavaCompatibleArrayList(this)); } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); for (int i = 0; i < size; i++) { builder.append(array[i]).append(", "); } return builder.toString(); } } public static class JavaCompatibleArrayList extends java.util.AbstractList implements java.util.RandomAccess { private List.ArrayList list = null; public JavaCompatibleArrayList(List.ArrayList list) { this.list = list; } /** * {@inheritDoc} */ @Override public boolean add(T value) { return list.add(value); } /** * {@inheritDoc} */ @Override public boolean remove(Object value) { return list.remove((T)value); } /** * {@inheritDoc} */ @Override public boolean contains(Object value) { return list.contains((T)value); } /** * {@inheritDoc} */ @Override public int size() { return list.size; } /** * {@inheritDoc} */ @Override public void add(int index, T value) { list.add(index, value); } /** * {@inheritDoc} */ @Override public T remove(int index) { return list.remove(index); } /** * {@inheritDoc} */ @Override public T get(int index) { T t = list.get(index); if (t!=null) return t; throw new IndexOutOfBoundsException(); } /** * {@inheritDoc} */ @Override public T set(int index, T value) { return list.set(index, value); } } /** * Linked List (Singly link). A linked list is a data structure consisting * of a group of nodes which together represent a sequence. * * http://en.wikipedia.org/wiki/Linked_list * * @author Justin Wetherell */ public static class SinglyLinkedList extends List { private int size = 0; private Node head = null; private Node tail = null; /** * {@inheritDoc} */ @Override public boolean add(T value) { return add(new Node(value)); } /** * Add node to list. * * @param node * to add to list. */ private boolean add(Node node) { if (head == null) { head = node; tail = node; } else { Node prev = tail; prev.next = node; tail = node; } size++; return true; } /** * {@inheritDoc} */ @Override public boolean remove(T value) { // Find the node Node prev = null; Node node = head; while (node != null && (!node.value.equals(value))) { prev = node; node = node.next; } if (node == null) return false; // Update the tail, if needed if (node.equals(tail)) { tail = prev; if (prev != null) prev.next = null; } Node next = node.next; if (prev != null && next != null) { prev.next = next; } else if (prev != null && next == null) { prev.next = null; } else if (prev == null && next != null) { // Node is the head head = next; } else { // prev==null && next==null head = null; } size--; return true; } /** * {@inheritDoc} */ @Override public void clear() { head = null; size = 0; } /** * {@inheritDoc} */ @Override public boolean contains(T value) { Node node = head; while (node != null) { if (node.value.equals(value)) return true; node = node.next; } return false; } /** * {@inheritDoc} */ @Override public int size() { return size; } /** * {@inheritDoc} */ @Override public boolean validate() { java.util.Set keys = new java.util.HashSet(); Node node = head; if (node != null) { keys.add(node.value); Node child = node.next; while (child != null) { if (!validate(child,keys)) return false; child = child.next; } } return (keys.size()==size); } private boolean validate(Node node, java.util.Set keys) { if (node.value==null) return false; keys.add(node.value); Node child = node.next; if (child==null) { if (!node.equals(tail)) return false; } return true; } /** * {@inheritDoc} */ @Override public java.util.List toList() { return (new JavaCompatibleSinglyLinkedList(this)); } /** * {@inheritDoc} */ @Override public java.util.Collection toCollection() { return (new JavaCompatibleSinglyLinkedList(this)); } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); Node node = head; while (node != null) { builder.append(node.value).append(", "); node = node.next; } return builder.toString(); } private static class Node { private T value = null; private Node next = null; private Node() { } private Node(T value) { this.value = value; } /** * {@inheritDoc} */ @Override public String toString() { return "value=" + value + " next=" + ((next != null) ? next.value : "NULL"); } } } /** * Linked List (singly link). A linked list is a data structure consisting * of a group of nodes which together represent a sequence. * * http://en.wikipedia.org/wiki/Linked_list * * @author Justin Wetherell */ public static class JavaCompatibleSinglyLinkedList extends java.util.AbstractSequentialList { private List.SinglyLinkedList list = null; public JavaCompatibleSinglyLinkedList(List.SinglyLinkedList list) { this.list = list; } /** * {@inheritDoc} */ @Override public boolean add(T value) { return list.add(value); } /** * {@inheritDoc} */ @Override public boolean remove(Object value) { return list.remove((T)value); } /** * {@inheritDoc} */ @Override public boolean contains(Object value) { return list.contains((T)value); } /** * {@inheritDoc} */ @Override public int size() { return list.size(); } /** * {@inheritDoc} */ @Override public java.util.ListIterator listIterator(int index) { return (new SinglyLinkedListListIterator(list)); } private static class SinglyLinkedListListIterator implements java.util.ListIterator { private int index = 0; private SinglyLinkedList list = null; private SinglyLinkedList.Node prev = null; private SinglyLinkedList.Node next = null; private SinglyLinkedList.Node last = null; private SinglyLinkedListListIterator(SinglyLinkedList list) { this.list = list; this.next = list.head; this.prev = null; this.last = null; } /** * {@inheritDoc} */ @Override public void add(T value) { SinglyLinkedList.Node node = new SinglyLinkedList.Node(value); if (list.head == null) { list.head = node; list.tail = node; } else { SinglyLinkedList.Node p = null; SinglyLinkedList.Node n = list.head; while (n!= null && !(n.equals(next))) { p = node; n = node.next; } if (p != null) { p.next = node; } else { // replacing head list.head = node; } node.next = n; } this.next = node; list.size++; } /** * {@inheritDoc} */ @Override public void remove() { if (last == null) return; SinglyLinkedList.Node p = null; SinglyLinkedList.Node node = this.last; while (node!= null && !(node.equals(last))) { p = node; node = node.next; } SinglyLinkedList.Node n = last.next; if (p != null) p.next = n; if (last.equals(list.head)) list.head = n; if (last.equals(list.tail)) list.tail = p; list.size--; } /** * {@inheritDoc} */ @Override public void set(T value) { if (last != null) last.value = value; } /** * {@inheritDoc} */ @Override public boolean hasNext() { return (next!=null); } /** * {@inheritDoc} */ @Override public boolean hasPrevious() { return (prev!=null); } /** * {@inheritDoc} */ @Override public int nextIndex() { return index; } /** * {@inheritDoc} */ @Override public int previousIndex() { return index-1; } /** * {@inheritDoc} */ @Override public T next() { if (next == null) throw new java.util.NoSuchElementException(); index++; last = next; prev = next; next = next.next; return last.value; } /** * {@inheritDoc} */ @Override public T previous() { if (prev == null) throw new java.util.NoSuchElementException(); index--; last = prev; next = prev; SinglyLinkedList.Node p = null; SinglyLinkedList.Node node = this.list.head; while (node!= null && !(node.equals(prev))) { p = node; node = node.next; } prev = p; return last.value; } } } /** * Linked List (doubly link). A linked list is a data structure consisting * of a group of nodes which together represent a sequence. * * http://en.wikipedia.org/wiki/Linked_list * * @author Justin Wetherell */ public static class DoublyLinkedList extends List { private int size = 0; private Node head = null; private Node tail = null; /** * {@inheritDoc} */ @Override public boolean add(T value) { return add(new Node(value)); } /** * Add node to list. * * @param node * to add to list. */ private boolean add(Node node) { if (head == null) { head = node; tail = node; } else { Node prev = tail; prev.next = node; node.prev = prev; tail = node; } size++; return true; } /** * {@inheritDoc} */ @Override public boolean remove(T value) { // Find the node Node node = head; while (node != null && (!node.value.equals(value))) { node = node.next; } if (node == null) return false; // Update the tail, if needed if (node.equals(tail)) tail = node.prev; Node prev = node.prev; Node next = node.next; if (prev != null && next != null) { prev.next = next; next.prev = prev; } else if (prev != null && next == null) { prev.next = null; } else if (prev == null && next != null) { // Node is the head next.prev = null; head = next; } else { // prev==null && next==null head = null; } size--; return true; } /** * {@inheritDoc} */ @Override public void clear() { head = null; size = 0; } /** * {@inheritDoc} */ @Override public boolean contains(T value) { Node node = head; while (node != null) { if (node.value.equals(value)) return true; node = node.next; } return false; } /** * {@inheritDoc} */ @Override public int size() { return size; } /** * {@inheritDoc} */ @Override public boolean validate() { java.util.Set keys = new java.util.HashSet(); Node node = head; if (node!=null) { keys.add(node.value); if (node.prev!=null) return false; Node child = node.next; while (child!=null) { if (!validate(child,keys)) return false; child = child.next; } } return (keys.size()==size); } private boolean validate(Node node, java.util.Set keys) { if (node.value==null) return false; keys.add(node.value); Node child = node.next; if (child!=null) { if (!child.prev.equals(node)) return false; } else { if (!node.equals(tail)) return false; } return true; } /** * {@inheritDoc} */ @Override public java.util.List toList() { return (new JavaCompatibleDoublyLinkedList(this)); } /** * {@inheritDoc} */ @Override public java.util.Collection toCollection() { return (new JavaCompatibleDoublyLinkedList(this)); } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); Node node = head; while (node != null) { builder.append(node.value).append(", "); node = node.next; } return builder.toString(); } private static class Node { private T value = null; private Node prev = null; private Node next = null; private Node() { } private Node(T value) { this.value = value; } /** * {@inheritDoc} */ @Override public String toString() { return "value=" + value + " previous=" + ((prev != null) ? prev.value : "NULL") + " next=" + ((next != null) ? next.value : "NULL"); } } } public static class JavaCompatibleDoublyLinkedList extends java.util.AbstractSequentialList { private List.DoublyLinkedList list = null; public JavaCompatibleDoublyLinkedList(List.DoublyLinkedList list) { this.list = list; } /** * {@inheritDoc} */ @Override public boolean add(T value) { return list.add(value); } /** * {@inheritDoc} */ @Override public boolean remove(Object value) { return list.remove((T)value); } /** * {@inheritDoc} */ @Override public boolean contains(Object value) { return list.contains((T)value); } /** * {@inheritDoc} */ @Override public int size() { return list.size(); } /** * {@inheritDoc} */ @Override public java.util.ListIterator listIterator(int index) { return (new DoublyLinkedListListIterator(list)); } private static class DoublyLinkedListListIterator implements java.util.ListIterator { private int index = 0; private DoublyLinkedList list = null; private DoublyLinkedList.Node prev = null; private DoublyLinkedList.Node next = null; private DoublyLinkedList.Node last = null; private DoublyLinkedListListIterator(DoublyLinkedList list) { this.list = list; this.next = list.head; this.prev = null; this.last = null; } /** * {@inheritDoc} */ @Override public void add(T value) { DoublyLinkedList.Node node = new DoublyLinkedList.Node(value); DoublyLinkedList.Node n = this.next; if (this.prev != null) this.prev.next = node; node.prev = this.prev; node.next = n; if (n != null) n.prev = node; this.next = node; if (this.prev == null) list.head = node; // new root list.size++; } /** * {@inheritDoc} */ @Override public void remove() { if (last == null) return; DoublyLinkedList.Node p = last.prev; DoublyLinkedList.Node n = last.next; if (p != null) p.next = n; if (n != null) n.prev = p; if (last.equals(list.head)) list.head = n; if (last.equals(list.tail)) list.tail = p; list.size--; } /** * {@inheritDoc} */ @Override public void set(T value) { if (last != null) last.value = value; } /** * {@inheritDoc} */ @Override public boolean hasNext() { return (next!=null); } /** * {@inheritDoc} */ @Override public boolean hasPrevious() { return (prev!=null); } /** * {@inheritDoc} */ @Override public int nextIndex() { return index; } /** * {@inheritDoc} */ @Override public int previousIndex() { return index-1; } /** * {@inheritDoc} */ @Override public T next() { if (next == null) throw new java.util.NoSuchElementException(); index++; last = next; prev = next; next = next.next; return last.value; } /** * {@inheritDoc} */ @Override public T previous() { if (prev == null) throw new java.util.NoSuchElementException(); index--; last = prev; next = prev; prev = next.prev; return last.value; } } } }