You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

688 lines
18 KiB
Java

package com.jwetherell.algorithms.data_structures;
import com.jwetherell.algorithms.data_structures.interfaces.IQueue;
@SuppressWarnings("unchecked")
public interface Queue<T> extends IQueue<T> {
/**
* This queue implementation is backed by an array.
*
* @author Justin Wetherell <phishman3579@gmail.com>
*/
public static class ArrayQueue<T> implements Queue<T> {
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<array.length; i++) {
T t = array[i];
if ((realFirst==realLast) ||
(realFirst<realLast && (i>=realFirst && i<realLast)) ||
(realLast<realFirst && (i<realLast || 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<T> toQueue() {
return (new JavaCompatibleArrayQueue<T>(this));
}
/**
* {@inheritDoc}
*/
@Override
public java.util.Collection<T> toCollection() {
return (new JavaCompatibleArrayQueue<T>(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 <phishman3579@gmail.com>
*/
public static class LinkedQueue<T> implements Queue<T> {
private Node<T> head = null;
private Node<T> 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<T>(value));
}
/**
* Enqueue the node in the queue.
*
* @param node
* to enqueue.
*/
private boolean add(Node<T> node) {
if (head == null) {
head = node;
tail = node;
} else {
Node<T> 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<T> 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<T> node = head;
while (node != null && (!node.value.equals(value))) {
node = node.next;
}
if (node == null) return false;
return remove(node);
}
private boolean remove(Node<T> node) {
// Update the tail, if needed
if (node.equals(tail))
tail = node.prev;
Node<T> prev = node.prev;
Node<T> 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<T> 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<T> keys = new java.util.HashSet<T>();
Node<T> node = head;
if (node!=null) {
keys.add(node.value);
if (node.prev!=null) return false;
Node<T> child = node.next;
while (child!=null) {
if (!validate(child,keys)) return false;
child = child.next;
}
}
return (keys.size()==size());
}
private boolean validate(Node<T> node, java.util.Set<T> keys) {
if (node.value==null) return false;
keys.add(node.value);
Node<T> 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<T> toQueue() {
return (new JavaCompatibleLinkedQueue<T>(this));
}
/**
* {@inheritDoc}
*/
@Override
public java.util.Collection<T> toCollection() {
return (new JavaCompatibleLinkedQueue<T>(this));
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
Node<T> node = head;
while (node != null) {
builder.append(node.value).append(", ");
node = node.next;
}
return builder.toString();
}
private static class Node<T> {
private T value = null;
private Node<T> prev = null;
private Node<T> 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<T> extends java.util.AbstractQueue<T> {
private ArrayQueue<T> queue = null;
public JavaCompatibleArrayQueue(ArrayQueue<T> 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<T> iterator() {
return (new ArrayQueueIterator<T>(queue));
}
private static class ArrayQueueIterator<T> implements java.util.Iterator<T> {
private ArrayQueue<T> queue = null;
private int last = -1;
private int index = 0; //offset from first
private ArrayQueueIterator(ArrayQueue<T> 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<T> extends java.util.AbstractQueue<T> {
private LinkedQueue<T> queue = null;
public JavaCompatibleLinkedQueue(LinkedQueue<T> 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<T> iterator() {
return (new LinkedQueueIterator<T>(queue));
}
private static class LinkedQueueIterator<T> implements java.util.Iterator<T> {
private LinkedQueue<T> queue = null;
private LinkedQueue.Node<T> lastNode = null;
private LinkedQueue.Node<T> nextNode = null;
private LinkedQueueIterator(LinkedQueue<T> queue) {
this.queue = queue;
this.nextNode = queue.tail;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return (nextNode!=null);
}
/**
* {@inheritDoc}
*/
@Override
public T next() {
LinkedQueue.Node<T> current = nextNode;
lastNode = current;
if (current!=null) {
nextNode = current.prev;
return current.value;
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public void remove() {
queue.remove(lastNode);
}
}
}
}