package com.hithomelabs.princeton1.module4; import java.util.Iterator; import javax.annotation.Nonnull; public class ArrayQueue extends Queue{ // insertion from tail, removal from head public static final int DEFAULT_CAPACITY = 10; private int capacity; private int tail; private int head; private int size; private E[] arr; public ArrayQueue(){ this(DEFAULT_CAPACITY); } public ArrayQueue(int capacity){ this.capacity = capacity; arr = (E[]) new Object[this.capacity]; size = 0; } @Override public boolean isEmpty() { return size == 0; } @Override public E dequeue() { if(isEmpty()) return null; else{ E element = arr[head]; // Garbage collection arr[head] = null; head = (head+1)%capacity; size = size - 1; if(capacity >= 40 && size < capacity/4){ capacity = capacity/2; resize(capacity, capacity*2); } return element; } } @Override public void enqueue(E element) { // We plan capacity expansion if needed if (size == capacity){ capacity = capacity * 2; resize(capacity, capacity/2); } arr[tail] = element; tail = (tail + 1) % capacity; ++size; } // When resize takes place always the original array is full, so copy the complete array as is private void resize(int capacity, int oldCapacity) { E[] resizedArr = (E[]) new Object[capacity]; for(int i = 0; i < size; i++) { resizedArr[i] = arr[head]; // halving because capacity has now doubled arr[head] = null; head = (head + 1) % oldCapacity; } arr = resizedArr; // When resizing takes place, we bring the head to 0 and the tail to size // tail is where new inserts will be made and head will be where elements will be removed tail = size; head = 0; } @Override public int size() { return size; } @Override @Nonnull public Iterator iterator() { return new Iterator() { int counter = size; int pointer = head; @Override public boolean hasNext() { return counter != 0; } @Override public E next() { E element = arr[pointer]; pointer = (pointer + 1)% capacity; --counter; return element; } }; } }