package com.jwetherell.algorithms.data_structures; import com.jwetherell.algorithms.data_structures.interfaces.IQueue; @SuppressWarnings("unchecked") public interface Queue extends IQueue { /** * This queue implementation is backed by an array. * * @author Justin Wetherell */ public static class ArrayQueue implements Queue { private static final int MINIMUM_SIZE = 1024; private T[] array = (T[]) new Object[MINIMUM_SIZE]; private int lastIndex = 0; private int firstIndex = 0; /** * {@inheritDoc} */ @Override public boolean offer(T value) { if (size() >= array.length) grow(size()); array[lastIndex % array.length] = value; lastIndex++; return true; } /** * {@inheritDoc} */ @Override public T poll() { int size = lastIndex - firstIndex; if (size < 0) return null; T t = array[firstIndex % array.length]; array[firstIndex % array.length] = null; firstIndex++; size = lastIndex - firstIndex; if (size <= 0) { // Removed last element lastIndex = 0; firstIndex = 0; } int shrinkSize = array.length>>1; if (shrinkSize >= MINIMUM_SIZE && size < shrinkSize) shrink(); return t; } /** * {@inheritDoc} */ @Override public T peek() { return array[firstIndex % array.length]; } /** * {@inheritDoc} */ @Override public boolean remove(T value) { for (int i=0; i < array.length; i++) { T obj = array[i]; // if obj is null, it should return false (not NPE) if (value.equals(obj)) return remove(i); } return false; } private boolean remove(int index) { if (index<0 || index >= array.length) return false; if (index==firstIndex) return (poll()!=null); int adjIndex = index % array.length; int adjLastIndex = (lastIndex-1) % array.length; if (adjIndex != adjLastIndex) { // Shift the array down one spot System.arraycopy(array, index+1, array, index, (array.length - (index+1))); if (adjLastIndex < firstIndex) { //Wrapped around array array[array.length-1] = array[0]; System.arraycopy(array, 1, array, 0, firstIndex-1); } } array[adjLastIndex] = null; int shrinkSize = array.length>>1; if (shrinkSize >= MINIMUM_SIZE && size() < shrinkSize) shrink(); lastIndex--; return true; } // Grow the array by 50% and rearrange to make sequential private void grow(int size) { int growSize = (size + (size<<1)); T[] temp = (T[]) new Object[growSize]; // Since the array can wrap around, make sure you grab the first chunk int adjLast = lastIndex % array.length; if (adjLast < firstIndex) { System.arraycopy(array, 0, temp, array.length-adjLast, adjLast+1); } // Copy the remaining System.arraycopy(array, firstIndex, temp, 0, array.length-firstIndex); array = null; array = temp; lastIndex = (lastIndex - firstIndex); firstIndex = 0; } // Shrink the array by 50% and rearrange to make sequential private void shrink() { int shrinkSize = array.length>>1; T[] temp = (T[]) new Object[shrinkSize]; // Since the array can wrap around, make sure you grab the first chunk int adjLast = lastIndex % array.length; int endIndex = (lastIndex>array.length)?array.length:lastIndex; if (adjLast <= firstIndex) { System.arraycopy(array, 0, temp, array.length-firstIndex, adjLast); } // Copy the remaining System.arraycopy(array, firstIndex, temp, 0, endIndex-firstIndex); array = null; array = temp; lastIndex = (lastIndex - firstIndex); firstIndex = 0; } /** * {@inheritDoc} */ @Override public void clear() { firstIndex = 0; lastIndex = 0; } /** * {@inheritDoc} */ @Override public boolean contains(T value) { for (int i=0; i < array.length; i++) { T obj = array[i]; // if obj is null, it should return false (not NPE) if (value.equals(obj)) return true; } return false; } /** * {@inheritDoc} */ @Override public boolean validate() { if (size()==0) return true; int localSize = 0; int realFirst = firstIndex; if (firstIndex>array.length) realFirst = firstIndex%array.length; int realLast = lastIndex; if (lastIndex>array.length) realLast = lastIndex%array.length; for (int i=0; i=realFirst && i=realFirst)) ) { if (t==null) return false; localSize++; } else { if (t!=null) return false; } } return (localSize==size()); } /** * {@inheritDoc} */ @Override public int size() { return lastIndex - firstIndex; } /** * {@inheritDoc} */ @Override public java.util.Queue toQueue() { return (new JavaCompatibleArrayQueue(this)); } /** * {@inheritDoc} */ @Override public java.util.Collection toCollection() { return (new JavaCompatibleArrayQueue(this)); } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); for (int i = lastIndex - 1; i >= firstIndex; i--) { builder.append(array[i%array.length]).append(", "); } return builder.toString(); } } /** * This queue implementation is backed by a linked list. * * @author Justin Wetherell */ public static class LinkedQueue implements Queue { private Node head = null; private Node tail = null; private int size = 0; public LinkedQueue() { head = null; tail = null; size = 0; } /** * {@inheritDoc} */ @Override public boolean offer(T value) { return add(new Node(value)); } /** * Enqueue the node in the queue. * * @param node * to enqueue. */ private boolean add(Node node) { if (head == null) { head = node; tail = node; } else { Node oldHead = head; head = node; node.next = oldHead; oldHead.prev = node; } size++; return true; } /** * {@inheritDoc} */ @Override public T poll() { T result = null; if (tail != null) { result = tail.value; Node prev = tail.prev; if (prev != null) { prev.next = null; tail = prev; } else { head = null; tail = null; } size--; } return result; } /** * {@inheritDoc} */ @Override public T peek() { return (tail!=null)?tail.value:null; } /** * {@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; return remove(node); } private boolean remove(Node node) { // 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) { if (head == null) return false; 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; if (!validate(child,keys)) return false; } else { if (!node.equals(tail)) return false; } return true; } /** * {@inheritDoc} */ @Override public java.util.Queue toQueue() { return (new JavaCompatibleLinkedQueue(this)); } /** * {@inheritDoc} */ @Override public java.util.Collection toCollection() { return (new JavaCompatibleLinkedQueue(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(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 JavaCompatibleArrayQueue extends java.util.AbstractQueue { private ArrayQueue queue = null; public JavaCompatibleArrayQueue(ArrayQueue queue) { this.queue = queue; } /** * {@inheritDoc} */ @Override public boolean add(T value) { return queue.offer(value); } /** * {@inheritDoc} */ @Override public boolean remove(Object value) { return queue.remove((T)value); } /** * {@inheritDoc} */ @Override public boolean contains(Object value) { return queue.contains((T)value); } /** * {@inheritDoc} */ @Override public boolean offer(T value) { return queue.offer(value); } /** * {@inheritDoc} */ @Override public T peek() { return queue.peek(); } /** * {@inheritDoc} */ @Override public T poll() { return queue.poll(); } /** * {@inheritDoc} */ @Override public int size() { return queue.size(); } /** * {@inheritDoc} */ @Override public java.util.Iterator iterator() { return (new ArrayQueueIterator(queue)); } private static class ArrayQueueIterator implements java.util.Iterator { private ArrayQueue queue = null; private int last = -1; private int index = 0; //offset from first private ArrayQueueIterator(ArrayQueue queue) { this.queue = queue; } /** * {@inheritDoc} */ @Override public boolean hasNext() { return ((queue.firstIndex+index) < queue.lastIndex); } /** * {@inheritDoc} */ @Override public T next() { if (queue.firstIndex+index < queue.lastIndex) { last = queue.firstIndex+index; return queue.array[queue.firstIndex+index++]; } return null; } /** * {@inheritDoc} */ @Override public void remove() { queue.remove(last); } } } public static class JavaCompatibleLinkedQueue extends java.util.AbstractQueue { private LinkedQueue queue = null; public JavaCompatibleLinkedQueue(LinkedQueue queue) { this.queue = queue; } /** * {@inheritDoc} */ @Override public boolean add(T value) { return queue.offer(value); } /** * {@inheritDoc} */ @Override public boolean remove(Object value) { return queue.remove((T)value); } /** * {@inheritDoc} */ @Override public boolean contains(Object value) { return queue.contains((T)value); } /** * {@inheritDoc} */ @Override public boolean offer(T value) { return queue.offer(value); } /** * {@inheritDoc} */ @Override public T peek() { return queue.peek(); } /** * {@inheritDoc} */ @Override public T poll() { return queue.poll(); } /** * {@inheritDoc} */ @Override public int size() { return queue.size(); } /** * {@inheritDoc} */ @Override public java.util.Iterator iterator() { return (new LinkedQueueIterator(queue)); } private static class LinkedQueueIterator implements java.util.Iterator { private LinkedQueue queue = null; private LinkedQueue.Node lastNode = null; private LinkedQueue.Node nextNode = null; private LinkedQueueIterator(LinkedQueue queue) { this.queue = queue; this.nextNode = queue.tail; } /** * {@inheritDoc} */ @Override public boolean hasNext() { return (nextNode!=null); } /** * {@inheritDoc} */ @Override public T next() { LinkedQueue.Node current = nextNode; lastNode = current; if (current!=null) { nextNode = current.prev; return current.value; } return null; } /** * {@inheritDoc} */ @Override public void remove() { queue.remove(lastNode); } } } }