Mort's Original Code

public class LinkedList<T>
{
    private T data;
    private LinkedList<T> prevNode, nextNode;

    /**
     *  Constructs a new element
     *
     * @param  data, data of object
     * @param  node, previous node
     */
    public LinkedList(T data, LinkedList<T> node)
    {
        this.setData(data);
        this.setPrevNode(node);
        this.setNextNode(null);
    }

    /**
     *  Clone an object,
     *
     * @param  node  object to clone
     */
    public LinkedList(LinkedList<T> node)
    {
        this.setData(node.data);
        this.setPrevNode(node.prevNode);
        this.setNextNode(node.nextNode);
    }

    /**
     *  Setter for T data in DoubleLinkedNode object
     *
     * @param  data, update data of object
     */
    public void setData(T data)
    {
        this.data = data;
    }

    /**
     *  Returns T data for this element
     *
     * @return  data associated with object
     */
    public T getData()
    {
        return this.data;
    }

    /**
     *  Setter for prevNode in DoubleLinkedNode object
     *
     * @param node, prevNode to current Object
     */
    public void setPrevNode(LinkedList<T> node)
    {
        this.prevNode = node;
    }

    /**
     *  Setter for nextNode in DoubleLinkedNode object
     *
     * @param node, nextNode to current Object
     */
    public void setNextNode(LinkedList<T> node)
    {
        this.nextNode = node;
    }


    /**
     *  Returns reference to previous object in list
     *
     * @return  the previous object in the list
     */
    public LinkedList<T> getPrevious()
    {
        return this.prevNode;
    }

    /**
     *  Returns reference to next object in list
     *
     * @return  the next object in the list
     */
    public LinkedList<T> getNext()
    {
        return this.nextNode;
    }

}

class QueueIterator<T> implements Iterator<T> {
    LinkedList<T> current;  // current element in iteration

    // QueueIterator is pointed to the head of the list for iteration
    public QueueIterator(LinkedList<T> head) {
        current = head;
    }

    // hasNext informs if next element exists
    public boolean hasNext() {
        return current != null;
    }

    // next returns data object and advances to next position in queue
    public T next() {
        T data = current.getData();
        current = current.getNext();
        return data;
    }
}

/**
 * Queue: custom implementation
 * @author     John Mortensen
 *
 * 1. Uses custom LinkedList of Generic type T
 * 2. Implements Iterable
 * 3. "has a" LinkedList for head and tail
 */
public class Queue<T> implements Iterable<T> {
    LinkedList<T> head = null, tail = null;

    /**
     *  Add a new object at the end of the Queue,
     *
     * @param  data,  is the data to be inserted in the Queue.
     */
    public void add(T data) {
        // add new object to end of Queue
        LinkedList<T> tail = new LinkedList<>(data, null);

        if (this.head == null)  // initial condition
            this.head = this.tail = tail;
        else {  // nodes in queue
            this.tail.setNextNode(tail); // current tail points to new tail
            this.tail = tail;  // update tail
        }
    }

    /**
     *  Returns the data of head.
     *
     * @return  data, the dequeued data
     */
    public T delete() {
        T data = this.peek();
        if (this.tail != null) { // initial condition
            this.head = this.head.getNext(); // current tail points to new tail
            if (this.head != null) {
                this.head.setPrevNode(tail);
            }
        }
        return data;
    }

    /**
     * Get the number of elements in the Queue.
     */
    public int size() {
        int count = 0;
        for (T data : this) {
            count++;
        }
        return count;
    }

    /* 
     * Returns true if Queue is empty.
     */
    public boolean isEmpty() {
        return this.head == null;
    }

    /**
     *  Return data in Queue.
     */
    public String toString() {
        String str = "";
        for (T data : this) {
            str += data + " ";
        }
        return str;
    }

    /**
     * Returns data as List.
     */
    public List<T> asList() {
        List<T> list = new ArrayList<>();
        for (T data : this) {
            list.add(data);
        }
        return list;
    }

    /**
     *  Returns the data of head.
     *
     * @return  this.head.getData(), the head data in Queue.
     */
    public T peek() {
        return this.head.getData();
    }

    /**
     *  Returns the head object.
     *
     * @return  this.head, the head object in Queue.
     */
    public LinkedList<T> getHead() {
        return this.head;
    }

    /**
     *  Returns the tail object.
     *
     * @return  this.tail, the last object in Queue
     */
    public LinkedList<T> getTail() {
        return this.tail;
    }

    /**
     *  Returns the iterator object.
     *
     * @return  this, instance of object
     */
    public Iterator<T> iterator() {
        return new QueueIterator<>(this.head);
    }
}

class QueueManager<T> {
    // queue data
    private final String name; // name of queue
    private int count = 0; // number of objects in queue
    public final Queue<T> queue = new Queue<>(); // queue object

    /**
     *  Queue constructor
     *  Title with empty queue
     */
    public QueueManager(String name) {
        this.name = name;
    }

    /**
     *  Queue constructor
     *  Title with series of Arrays of Objects
     */
    public QueueManager(String name, T[]... seriesOfObjects) {
        this.name = name;
        this.addList(seriesOfObjects);
    }

    /**
     * Add an element to queue
     */
    public void add(T data) {
        System.out.println("Enqueued data: " + data);
        this.queue.add(data);
        this.count++;
    }

    /**
     * Add a list of objects to queue
     */
    public void addList(T[]... seriesOfObjects) {  //accepts multiple generic T lists
        for (T[] objects: seriesOfObjects)
            for (T data : objects) {
                this.queue.add(data);
                this.count++;
            }
    }

    /**
     * Delete an element from queue
     */
    public void delete() {
        // print data else print null
        System.out.println("Dequeued data: " + this.queue.delete());
        this.count--;
    }

    /**
     * Print any array objects from queue
     */
    public void printQueue() {
        System.out.print(this.name + " count: " + count + ", data: ");
        for (T data : queue)
            System.out.print(data + " ");
        System.out.println();
    }
}

class QueueTester {
    public static void main(String[] args)
    {
        // Create iterable Queue of Words
        Object[] words = new String[] { "seven", "slimy", "snakes", "sallying", "slowly", "slithered", "southward"};
        QueueManager qWords = new QueueManager("Words", words);
        qWords.printQueue();

        // Create iterable Queue of Integers
        Object[] numbers = new Integer[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        QueueManager qNums = new QueueManager("Integers", numbers );
        qNums.printQueue();

        // // Create iterable Queue of NCS Generics
        // Animal.setOrder(Animal.KeyType.name);
        // Alphabet.setOrder(Alphabet.KeyType.letter);
        // Cupcake.setOrder(Cupcake.KeyType.flavor);
        // // Illustrates use of a series of repeating arguments
        // QueueManager qGenerics = new QueueManager("My Generics",
        //         Alphabet.alphabetData(),
        //         Animal.animals(),
        //         Cupcake.cupcakes()
        // );
        // qGenerics.printQueue();

        // // Create iterable Queue of Mixed types of data
        // QueueManager qMix = new QueueManager("Mixed");
        // qMix.queue.add("Start");
        // qMix.addList(
        //         words,
        //         numbers,
        //         Alphabet.alphabetData(),
        //         Animal.animals(),
        //         Cupcake.cupcakes()
        // );
        // qMix.queue.add("End");
        // qMix.printQueue();
    }
}
QueueTester.main(null);
Words count: 7, data: seven slimy snakes sallying slowly slithered southward 
Integers count: 10, data: 0 1 2 3 4 5 6 7 8 9 

Queues and Stacks

A queue is an interface that orders data in a FIFO (first in first out) order. A stack is very similar, but instead works in a LIFO (last in first out) order.

Generics

A generic is a way to declare that the parameter data type for either methods, classes, or intefaces is unknown, and allows them to handle different types of data. Generics allow us to use methods,classes and interfaces in a more generalized way, instead of limiting ourselves to certain data types. Note that T is a placeholder, and can be replaced with almost anything so long as it is not a data type (int, char, etc...).

Challenge 1

Add and Delete elements from Queue. Working with the code that is given, you will need to adjust Add and write Delete, to output from the Queue as follows.

public class QueueTester {
    public static void main(String[] args) {
      QueueManager qWords = new QueueManager("Words");   
      Object[] words = new String[] { "word1", "word2", "word3", "word4", "word5", "word6", "word7"};
  
      for (Object word : words) { // progressively adds words to the queue until all words have been added
        qWords.add(word);
        qWords.printQueue();
      }
  
      for (int i = 0; i < words.length; i++) { // progressively deletes words from queue
        qWords.delete();
        qWords.printQueue();
      }
    }
  }
  
  QueueTester.main(null);
|         QueueManager qWords = new QueueManager("Words");   
cannot find symbol
  symbol:   class QueueManager

|         QueueManager qWords = new QueueManager("Words");   
cannot find symbol
  symbol:   class QueueManager

|         for (String word : words) {
incompatible types: java.lang.Object cannot be converted to java.lang.String

|             wordStack.push(word);
unchecked call to push(E) as a member of the raw type java.util.Stack