LMU ☀️ CMSI 2120
DATA STRUCTURES
HOMEWORK #2 PARTIAL ANSWERS
ExpandableArrayStack.java
import java.util.NoSuchElementException;

/**
 * An implementation of a stack using a "expandable" array, i.e., whenever the
 * array would overflow, a new larger array is allocated and the elements are
 * copied into the new array. A new smaller array is used whenever the queue
 * gets too sparse as well.
 */
public class ExpandableArrayStack implements Stack {
    private static final int MINIMUM_CAPACITY = 16;

    private Object[] elements = new Object[MINIMUM_CAPACITY];
    private int size = 0;

    public void push(Object item) {
        if (size == elements.length) {
            reallocate(elements.length * 2);
        }
        elements[size++] = item;
    }

    public Object pop() {
        var item = peek();
        if (size <= capacity() / 4 && capacity() > MINIMUM_CAPACITY) {
            reallocate(elements.length / 2);
        }
        elements[--size] = null;
        return item;
    }

    public Object peek() {
        if (isEmpty()) {
            throw new NoSuchElementException();
        }
        return elements[size - 1];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    public int size() {
        return size;
    }

    public int capacity() {
        return elements.length;
    }

    private void reallocate(int newSize) {
        Object[] newArray = new Object[newSize];
        System.arraycopy(elements, 0, newArray, 0, size);
        elements = newArray;
    }
}

ExpandableArrayQueue.java
import java.util.NoSuchElementException;

/**
 * An implementation of a queue using a "expandable" array, i.e., whenever the
 * array would overflow, a new larger array is allocated and the elements are
 * copied into the new array. A new smaller array is used whenever the queue
 * gets too sparse as well.
 */
public class ExpandableArrayQueue implements Queue {
    private static final int MINIMUM_CAPACITY = 16;

    private Object[] elements = new Object[MINIMUM_CAPACITY];
    private int size = 0;
    private int head = 0; // index of the current front item, if one exists
    private int tail = 0; // index of next item to be added

    public void enqueue(Object item) {
        if (size == elements.length) {
            reallocate(elements.length * 2);
        }
        elements[tail] = item;
        tail = (tail + 1) % elements.length;
        size++;
    }

    public Object dequeue() {
        var item = peek();
        if (size <= capacity() / 4 && capacity() > MINIMUM_CAPACITY) {
            reallocate(elements.length / 2);
        }
        elements[head] = null;
        head = (head + 1) % elements.length;
        size--;
        return item;
    }

    public Object peek() {
        if (isEmpty()) {
            throw new NoSuchElementException();
        }
        return elements[head];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    public int size() {
        return size;
    }

    public int capacity() {
        return elements.length;
    }

    /*
     * When reallocating, always make the new head 0.
     */
    private void reallocate(int newSize) {
        Object[] newArray = new Object[newSize];
        for (var i = 0; i < size(); i++) {
            newArray[i] = elements[(head + i) % capacity()];
        }
        head = 0;
        tail = size();
        elements = newArray;
    }
}