Week 26 Hacks
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);
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...).
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);