diff --git a/SDEV333-Term-Project.iml b/SDEV333-Term-Project.iml index c90834f..0f07f6c 100644 --- a/SDEV333-Term-Project.iml +++ b/SDEV333-Term-Project.iml @@ -4,8 +4,25 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Bag/Bag.java b/src/Bag/Bag.java new file mode 100644 index 0000000..4acb2e4 --- /dev/null +++ b/src/Bag/Bag.java @@ -0,0 +1,26 @@ +package Bag; + +/** + * An implementation of the Bag data structure + * @param Class may store various types of values + * @author Zalman I. + */ +public interface Bag extends Iterable { + /** + * Adds the given item to the bag + * @param item the item to be added + */ + void add(E item); + + /** + * Checks whether the bag is empty, and returns true/false accordingly + * @return true if the bag is empty; otherwise false + */ + boolean isEmpty(); + + /** + * Gets and returns the number of items stored in the bag + * @return the number of items stored in the bag + */ + int size(); +} \ No newline at end of file diff --git a/src/Bag/LinkedBag.java b/src/Bag/LinkedBag.java new file mode 100644 index 0000000..7aa66a1 --- /dev/null +++ b/src/Bag/LinkedBag.java @@ -0,0 +1,169 @@ +package Bag; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Implementation of a Bag using a "list" of nodes and a Bag interface for generics + * @param Class may store various types of values + * @author Zalman I. + */ +public class LinkedBag implements Bag { + /** + * A container which contains an item and a connection to another Node + */ + private class Node { + /** + * The item stored within the Node + */ + E item; + + /** + * The node this Node is pointing to + */ + Node next; + + /** + * Creates a node, and stores the given item within it + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + * + * @param item the item being stored in node + */ + public Node(E item) { + // store given item + this.item = item; + + // node starts off disconnected + next = null; + } + } + + /** + * The first node in bag + */ + private Node first; + + /** + * The number of items stored in this bag + */ + private int size; + + /** + * Constructs an empty LinkedBag + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + */ + public LinkedBag() { + // bag starts off empty + first = null; + size = 0; + } + + /** + * Adds the given item to the bag + * + * Runtime: O(1) as we can instantly add a new item to start of list via the first variable, + * regardless of how many nodes exist in bag. + * + * @param item the item to be added + */ + @Override + public void add(E item) { + // create new node containing given item + Node newNode = new Node(item); + + // if the bag is not empty + if(!isEmpty()) { + // point new node at first, so it isn't lost + newNode.next = first; + } + + // override first with newly created node + // (making new node first node in bag) + first = newNode; + + // account for new item in bag + size++; + } + + /** + * Checks whether the bag is empty, and returns true/false accordingly + * + * Runtime: O(1) as we are instantly accessing variables and checking a condition. + * This operation would always take the same runtime to conduct. + * + * @return true if the bag is empty; otherwise false + */ + @Override + public boolean isEmpty() { + return size == 0 && first == null; + } + + /** + * Gets and returns the number of items stored in the bag + * + * Runtime: O(1) as we are instantly retrieving a variable. + * This operation would always take the same runtime to conduct. + * + * @return the number of items stored in the bag + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new LinkedBagIterator(); + } + + /** + * Implementation of an Iterator for the LinkedBag class + */ + private class LinkedBagIterator implements Iterator + { + /** + * The current Node being tracked by the Iterator + */ + private Node current; + + /** + * Constructs a LinkedBag iterator, with the first node tracked first + */ + LinkedBagIterator() { + current = first; + } + + /** + * Checks if list contains another element, and returns true/false accordingly + * @return true if list contains another element; otherwise false + */ + public boolean hasNext() { + return current != null; + } + + /** + * Gets and returns the first item in the list + * @return the first item in the list + */ + public E next() { + if(!hasNext()) { + throw new NoSuchElementException(); + } + + // get first item of list + E currItem = current.item; + + // move on to the next item + current = current.next; + + return currItem; + } + } +} diff --git a/src/Bag/Stats.java b/src/Bag/Stats.java new file mode 100644 index 0000000..31a8df3 --- /dev/null +++ b/src/Bag/Stats.java @@ -0,0 +1,44 @@ +package Bag; + +import java.util.Scanner; + +public class Stats +{ + public static void main(String[] args) { + // setup storage bag + Bag numbers = new LinkedBag(); + + // setup scanner, taking in given string + Scanner line = new Scanner("100 99 101 120 98 107 109 81 101 90"); + + // run through line + while (line.hasNextDouble()) { + // get current item and add to bag + numbers.add(line.nextDouble()); + } + + // track number of items in bag + int size = numbers.size(); + + // run through bag and add up all items + double sum = 0.0; + for (double currNum : numbers) { + sum += currNum; + } + + // get the mean of all numbers in bag + double mean = sum / size; + + // clear total tracker and use again to calculate standard dev + sum = 0.0; + for (double currNum : numbers) { + sum += (currNum - mean) * (currNum - mean); + } + + double std = Math.sqrt(sum / (size - 1)); + + // display calculation results + System.out.printf("Mean: %.2f\n", mean); + System.out.printf("Std dev: %.2f\n", std); + } +} \ No newline at end of file diff --git a/src/Deque.java b/src/Examples/Deque.java similarity index 97% rename from src/Deque.java rename to src/Examples/Deque.java index 0107f47..a4d7714 100644 --- a/src/Deque.java +++ b/src/Examples/Deque.java @@ -1,3 +1,5 @@ +package Examples; + /** * Deque: double-ended queue API * Supports adding and removing items at both ends. diff --git a/src/MathSet.java b/src/Examples/MathSet.java similarity index 99% rename from src/MathSet.java rename to src/Examples/MathSet.java index 5b87e0d..d5b6ea0 100644 --- a/src/MathSet.java +++ b/src/Examples/MathSet.java @@ -1,3 +1,5 @@ +package Examples; + /** * MathSet API (interface / abstract data type) * represents a mathematical set. Sets in mathematics diff --git a/src/List/ArrayList.java b/src/List/ArrayList.java new file mode 100644 index 0000000..0f9db11 --- /dev/null +++ b/src/List/ArrayList.java @@ -0,0 +1,447 @@ +package List; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Implementation of an ArrayList using the List interface for generics + * @param Class may store various types of values + * @author Zalman I. + */ +public class ArrayList implements List { + /** + * An array used to store items placed within the ArrayList + */ + private E[] buffer; + + /** + * The number of items stored within buffer + */ + private int size; + + /** + * Constructs an ArrayList with an empty buffer, and a default max capacity of 10 items + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + */ + public ArrayList() { + // setup buffer with default max capacity of 10 + buffer = (E[]) new Object[10]; + + // no items are stored in buffer + size = 0; + } + + /** + * If all slots in buffer are full, double its max capacity + * + * Runtime: O(n) as it has to run through the buffer to copy over all items into a new array, + * therefore the runtime depends on the prior buffer's length + */ + private void doubleMaxCapacity() { + // if all buffer slots are filled + if(size == buffer.length) { + // create a new buffer, with double the capacity of the existing buffer + E[] newBuffer = (E[]) new Object[size * 2]; + + // run through previous buffer and copy over all items + for(int i = 0; i < buffer.length; i++) { + newBuffer[i] = buffer[i]; + } + + // replace buffer with newBuffer, now with double the length + buffer = newBuffer; + } + } + + /** + * Add item to the front. + * + * Runtime: O(1) in the case that buffer is empty, as only storage at index 0 occurs. + * Otherwise O(n) as the runtime depends on the number of items already in the list. If we need to resize, + * the buffer gets run through to copy over items. If not, we are still shifting over all existing items to the right. + * + * @param item the item to be added + */ + @Override + public void addFront(E item) { + // if the buffer already contains items + if(!isEmpty()) { + // if the buffer is full, increase max capacity + doubleMaxCapacity(); // O(n) + + // run through buffer backwards + for (int i = size; i > 0; i--) { + // get item at previous index and place in current index, + // thereby shifting all items to the left + buffer[i] = buffer[i - 1]; + } + } + + // add the given item at the now cleared index 0 + buffer[0] = item; + + // a new item has been added to buffer + size++; + } + + /** + * Add item to the back. + * + * Runtime: O(1) if buffer is empty/not full, as we are only accessing the final index to add an item. + * If the array is full O(n) as we need to run through buffer to copy over all items during resize. + * + * @param item the item to be added + */ + @Override + public void addBack(E item) { + // if the buffer is full, increase max capacity + doubleMaxCapacity(); + + // add the given item at final index + buffer[size] = item; + + // a new item has been added to buffer + size++; + } + + /** + * Add an item at specified index (position). + * + * Runtime: O(1) if the array is empty. Otherwise, O(n) as runtime will depend on array size, + * either for resizing or shifting over items to free up given index + * + * @param index the index where the item should be added + * @param item the item to be added + */ + @Override + public void add(int index, E item) { + // if the given index is out of range + if(index < 0 || index > size) { + throw new IndexOutOfBoundsException(index + " is not a valid index"); + } + + // if the buffer is full, increase max capacity + doubleMaxCapacity(); + + // run through buffer backwards, up to given index + for (int i = size; i > index; i--) { + // get item at previous index and place in current index, + // thereby shifting all items to the right + buffer[i] = buffer[i - 1]; + } + + // add the given item at current index + buffer[index] = item; + + // a new item has been added to buffer + size++; + } + + /** + * Get the item at a specified index. + * + * Runtime: O(1) as we can instantly access the given index to retrieve item, + * assuming index exists/buffer not empty. + * + * @param index the index where the item should be retrieved + * @return the item located at that index + */ + @Override + public E get(int index) { + // if the given index is out of range + if(index < 0 || index > size) { + throw new IndexOutOfBoundsException(index + " is not a valid index"); + } + + // if buffer contains no items, one cannot be retrieved + if(isEmpty()) { + throw new NoSuchElementException("Cannot retrieve item from empty List.ArrayList"); + } + + return buffer[index]; + } + + /** + * Set (save) an item at a specified index. Previous + * item at that index is overwritten. + * + * Runtime: O(1) as we can instantly access the given index to replace its item, + * assuming index exists/buffer not empty. + * + * @param index the index where the item should be saved + * @param item the item to be saved + */ + @Override + public void set(int index, E item) { + // if the given index is out of range + if(index < 0 || index > size) { + throw new IndexOutOfBoundsException(index + " is not a valid index"); + } + + // place the given item at the requested index + buffer[index] = item; + + // if the buffer is regarded as empty, account for new item placed at index 0 + if(isEmpty()) { + size++; + } + } + + /** + * Remove item at the front of the list. + * + * Runtime: O(n) as we are shifting over all items in buffer left to "remove" the item at index 0. + * + * @return the item that was removed + */ + @Override + public E removeFront() { + // if buffer contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot remove item from empty ArrayList"); + } + + // get requested item prior to removal + E requestedItem = buffer[0]; + + // run through buffer + for(int i = 0; i < size; i++) { + // replace item at current index with item at next index + buffer[i] = buffer[i + 1]; + } + + // account for removal of item + size--; + + return requestedItem; + } + + /** + * Remove item at the back of the list + * + * Runtime: O(1) as we can instantly access the final index and set its value to null. + * + * @return the item that was removed + */ + @Override + public E removeBack() { + // if buffer contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot remove item from empty ArrayList"); + } + + // get requested item prior to removal, accounting for index + E requestedItem = buffer[size - 1]; + + // clear the final item in buffer + buffer[size - 1] = null; + + // account for removal of item + size--; + + return requestedItem; + } + + /** + * Remove item from the list + * + * Runtime: O(n) as searching for the given item via indexOf results in running through buffer once. + * If searching reveals it exists, we then also have to shift over all items after it left to remove it. + * + * @param item the item to be removed + */ + @Override + public void remove(E item) { + // if buffer contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot remove item from empty ArrayList"); + } + + // find item in buffer and get its index + int index = indexOf(item); // O(n) + + // if item is not in buffer + if(index == -1) { + throw new NoSuchElementException("Given item is not located in ArrayList"); + } + + // otherwise, run through buffer, starting at given index + // and accounting for removal of requested item + for(int i = index; i <= size - 1; i++) { + // replace item at current index with item at next index + buffer[i] = buffer[i + 1]; + } + + // account for removal of item + size--; + } + + /** + * Gets and returns the index of the given item in buffer, if exists + * + * Runtime: O(n) as we could potentially run through the entire buffer when searching for the given item. + * + * @param item the item being searched for in buffer + * @return the index of given item in buffer if exists; otherwise -1 + */ + private int indexOf(E item) { + // run through buffer + for(int i = 0; i < buffer.length; i++) { + // check if item stored at current index is the specified item + if(item.equals(buffer[i])) { + // return the current index, as that is where the specified item is located + return i; + } + } + + // if the item does not exist in buffer + return -1; + } + + /** + * Remove item at a specified index. + * + * Runtime: O(n) as runtime will depend on the number of items after given index which we need to shift left. + * + * @param index the index where the item should be removed + * @return the item that was removed + */ + @Override + public E remove(int index) { + // if the given index is out of range + if(index < 0 || index > size) { + throw new IndexOutOfBoundsException(index + " is not a valid index"); + } + + // if buffer contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot remove item from empty ArrayList"); + } + + // get requested item prior to removal + E requestedItem = buffer[index]; + + // run through buffer, starting at given index + // and accounting for removal of requested item + for(int i = index; i <= size - 1; i++) { + // replace item at current index with item at next index + buffer[i] = buffer[i + 1]; + } + + // account for removal of item + size--; + + return requestedItem; + } + + /** + * Checks if an item is in the list. + * + * Runtime O(n) as searching for the item requires running through buffer, and depends on its location + * within/number of items before and after it. + * + * @param item the item to search for + * @return true if the item is in the list, false otherwise + */ + @Override + public boolean contains(E item) { + // run through buffer + for (int i = 0; i < size; i++) { + // check if item at current index of buffer is given item + if(item.equals(buffer[i])) { + // item was located + return true; + } + } + + // item could not be found + return false; + } + + /** + * Checks if the list is empty. + * + * Runtime: O(1) as we are instantly accessing a variable and checking a condition. + * This operation would always take the same runtime to conduct. + * + * @return true if the list is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Provides a count of the number of items in the list. + * + * Runtime: O(1) as we are instantly retrieving a variable. + * This operation would always take the same runtime to conduct. + * + * @return number of items in the list + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new ArrayListIterator(); + } + + /** + * Implementation of an Iterator for the ArrayIntList class + */ + private class ArrayListIterator implements Iterator { + /** + * The current index being tracked by the Iterator + */ + private int index; + + /** + * Constructs an ArrayIntList iterator with the index initialized to 0 + */ + ArrayListIterator() { + index = 0; + } + + /** + * Returns {@code true} if the iteration has more elements. + * (In other words, returns {@code true} if {@link #next} would + * return an element rather than throwing an exception.) + * + * @return {@code true} if the iteration has more elements + */ + @Override + public boolean hasNext() { + return index < size; + } + + /** + * Returns the next element in the iteration. + * + * @return the next element in the iteration + * @throws NoSuchElementException if the iteration has no more elements + */ + @Override + public E next() { + if(!hasNext()) { + throw new NoSuchElementException(); + } + + // get the item at current index of buffer + E currItem = buffer[index]; + + // move on to next element + index++; + + return currItem; + } + } +} \ No newline at end of file diff --git a/src/List/LinkedList.java b/src/List/LinkedList.java new file mode 100644 index 0000000..d828a26 --- /dev/null +++ b/src/List/LinkedList.java @@ -0,0 +1,531 @@ +package List; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Implementation of a LinkedList using the List interface for generics + * @param Class may store various types of values + * @author Zalman I. + */ +public class LinkedList implements List { + /** + * A container which contains an item and a connection to another Node + */ + private class Node { + /** + * The item stored within the Node + */ + E item; + + /** + * The node this Node is pointing to + */ + Node next; + + /** + * Creates a node, and stores the given item within it + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + * + * @param item the item being stored in node + */ + public Node(E item) { + // store given item + this.item = item; + + // node starts off disconnected + next = null; + } + } + + /** + * The first Node of the current LinkedList + */ + private Node head; + + /** + * The number of items stored in this LinkedList + */ + private int size; + + /** + * Constructs an empty LinkedList + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + */ + public LinkedList() { + // list starts off empty + head = null; + size = 0; + } + + /** + * Add item to the front. + * + * Runtime: O(1) as we can quickly access the front of list via the head variable, + * regardless of how many nodes follow it. + * + * @param item the item to be added + */ + @Override + public void addFront(E item) { + // create new node containing given item + Node newNode = new Node(item); + + // if the list is not empty + if(!isEmpty()) { + // point new node at head + newNode.next = head; + } + + // override head with newly created node + // (making new node first node in list) + head = newNode; + + // account for new item in list + size++; + } + + /** + * Add item to the back. + * + * Runtime: O(1) if the list is empty. Otherwise, O(n), as runtime depends on the number of nodes already + * in list we need to pass to reach the end. + * + * @param item the item to be added + */ + @Override + public void addBack(E item) { + // if list is empty + if(isEmpty()) { + // add item at front of list + addFront(item); + } + + // if list is not empty + else { + // create new node containing given item + Node newNode = new Node(item); + + // setup tracker and run to end of list + Node current = head; + + while(current.next != null) { + current = current.next; + } + + // point final node at new node + current.next = newNode; + + // account for new item in list + size++; + } + } + + /** + * Add an item at specified index (position). + * + * Runtime: O(1) if the given index is 0 as we use the addFront method. + * Otherwise O(n) as we may potentially have to traverse all the way to middle or end of list. + * + * @param index the index where the item should be added + * @param item the item to be added + */ + @Override + public void add(int index, E item) { + // if given index is out of range + if(index < 0 || index > size) { + throw new IndexOutOfBoundsException(index + " is not a valid index"); + } + + // if given index was at front or back, use those methods + else if(index == 0) { + addFront(item); // O(1) + } + + else if(index == size) { + addBack(item); // O(n) + } + + else { + // setup trackers + Node previous = null; + Node current = head; + int currIndex = 0; + + // run through list, up to given index + while(current != null && currIndex != index) { + // update trackers + previous = current; + current = current.next; + currIndex++; + } + + // place given item in new node + Node newNode = new Node(item); + + // update links of previous and current nodes to account for new node + previous.next = newNode; + newNode.next = current; + + // account for new item in list + size++; + } + } + + /** + * Get the item at a specified index. + * + * Runtime: O(n) as runtime will depend on how many nodes we need to pass in list to reach the requested index. + * + * @param index the index where the item should be retrieved + * @return the item located at that index + */ + @Override + public E get(int index) { + // if given index is out of range + if(index < 0 || index > size) { + throw new IndexOutOfBoundsException(index + " is not a valid index"); + } + + // if list is empty + if(isEmpty()) { + throw new NoSuchElementException("Cannot retrieve item from empty LinkedList"); + } + + // setup trackers + int currIndex = 0; + Node current = head; + + // run through list, up to given index + while(current != null && currIndex != index) { + // update trackers + current = current.next; + currIndex++; + } + + // return item at current node/index + return current.item; + } + + /** + * Set (save) an item at a specified index. Previous + * item at that index is overwritten. + * + * Runtime: O(1) if the list is empty as we use the addFront method. + * Otherwise, O(n) as runtime will depend on how many nodes we need to pass in list to reach the requested index. + * + * @param index the index where the item should be saved + * @param item the item to be saved + */ + @Override + public void set(int index, E item) { + // if the given index is out of range + if(index < 0 || index > size) { + throw new IndexOutOfBoundsException(index + " is not a valid index"); + } + + // if list is empty + if(isEmpty()) { + // add given item to list at front + addFront(item); + } + + else { + // setup trackers + int currIndex = 0; + Node current = head; + + // run through list, up to given index + while (current != null && currIndex != index) { + // update trackers + current = current.next; + currIndex++; + } + + // overwrite item in current node with given item + current.item = item; + } + } + + /** + * Remove item at the front of the list. + * + * Runtime: O(1) as we can quickly access the front of list via the head variable, + * regardless of how many nodes follow it. + * + * @return the item that was removed + */ + @Override + public E removeFront() { + // if list contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot remove item from empty LinkedList"); + } + + // get requested item from head + E requestedItem = head.item; + + // overwrite head with next item in sequence, + // if no next item, head will become null + head = head.next; + + // account for element removal + size--; + + return requestedItem; + } + + /** + * Remove item at the back of the list + * + * Runtime: O(n), as runtime depends on the number of nodes already in list we need to pass to reach the end. + * + * @return the item that was removed + */ + @Override + public E removeBack() { + // if list contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot remove item from empty LinkedList"); + } + + // setup trackers and run through list till second to last node + Node current = head; + + while(current.next.next != null) { + current = current.next; + } + + // get requested item from final node + E requestedItem = current.next.item; + + // update current node to stop tracking final node + current.next = null; + + // account for item removal + size--; + + return requestedItem; + } + + /** + * Remove item from the list + * + * Runtime: O(n) as we use the contains method to check if item exists, which may require running through entire list. + * If it does exist, we then use the remove method, which in the worse case also runs at O(n). + * + * @param item the item to be removed + */ + @Override + public void remove(E item) { + // if list contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot remove item from empty LinkedList"); + } + + // check if list contains given item - O(n) + if(!contains(item)) { + throw new NoSuchElementException("Given item is not located in LinkedList"); + } + + // setup trackers and flag + Node current = head; + int currIndex = 0; + boolean itemNotFound = true; + + // run through list until item is found + while(current != null && itemNotFound) { + // check if the current node contains given item + if(item.equals(current.item)) { + // call the other remove method on current index + remove(currIndex); + + // cease loop, item was found and removed + itemNotFound = false; + } + + // update trackers + current = current.next; + currIndex++; + } + } + + /** + * Remove item at a specified index. + * + * Runtime: O(1) if the given index is 0 as we use the addFront method. + * Otherwise, O(n) as we may potentially have to traverse all the way to middle or end of list to unlink a node. + * + * @param index the index where the item should be removed + * @return the item that was removed + */ + @Override + public E remove(int index) { + // if the given index is out of range + if(index < 0 || index > size) { + throw new IndexOutOfBoundsException(index + " is not a valid index"); + } + + // if list contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot remove item from empty LinkedList"); + } + + // if given index was at front or back, use those methods + else if(index == 0) { + return removeFront(); + } + + else if(index == size) { + return removeBack(); + } + + else { + // setup trackers + Node previous = null; + Node current = head; + int currIndex = 0; + + // run through list, up to given index + while(current != null && currIndex != index) { + // update trackers + previous = current; + current = current.next; + currIndex++; + } + + // get item stored in node at current index + E requestedItem = current.item; + + // point previous node at current's next node, + // thereby cutting out current + previous.next = current.next; + + // account for removal of item + size--; + + return requestedItem; + } + } + + /** + * Checks if an item is in the list. + * + * Runtime: O(n) as searching for the item may require running through most of, or the entire list + * + * @param item the item to search for + * @return true if the item is in the list, false otherwise + */ + @Override + public boolean contains(E item) { + // if list is not empty + if(!isEmpty()) { + // setup pointer + Node current = head; + + // run through list + while (current != null) { + // check if the current Node contains given item + if (item.equals(current.item)) { + // item was found + return true; + } + + // move on to next node + current = current.next; + } + } + + // item not located in list, or list empty + return false; + } + + /** + * Checks if the list is empty. + * + * Runtime: O(1) as we are instantly accessing some variables and checking a condition. + * This operation would always take the same runtime to conduct. + * + * @return true if the list is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return size == 0 && head == null; + } + + /** + * Provides a count of the number of items in the list. + * + * Runtime: O(1) as we are instantly retrieving a variable. + * This operation would always take the same runtime to conduct. + * + * @return number of items in the list + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new LinkedListIterator(); + } + + /** + * Implementation of an Iterator for the LinkedList class + */ + private class LinkedListIterator implements Iterator { + /** + * The current Node being tracked by the Iterator + */ + private Node current; + + /** + * Constructs a LinkedList iterator with the head tracked as the first Node + */ + LinkedListIterator() { + current = head; + } + + /** + * Returns {@code true} if the iteration has more elements. + * (In other words, returns {@code true} if {@link #next} would + * return an element rather than throwing an exception.) + * + * @return {@code true} if the iteration has more elements + */ + @Override + public boolean hasNext() { + return current != null; + } + + /** + * Returns the next element in the iteration. + * + * @return the next element in the iteration + * @throws NoSuchElementException if the iteration has no more elements + */ + @Override + public E next() { + if(!hasNext()) { + throw new NoSuchElementException(); + } + + // get the item stored in current node + E currItem = current.item; + + // move on to the next node + current = current.next; + + // return the current item + return currItem; + } + } +} diff --git a/src/List.java b/src/List/List.java similarity index 96% rename from src/List.java rename to src/List/List.java index 2bf4aef..cdf12a6 100644 --- a/src/List.java +++ b/src/List/List.java @@ -1,5 +1,7 @@ +package List; + /*** - * List interface (API / abstract data type) + * List.List interface (API / abstract data type) * @param Class or data type of the items in the list. */ public interface List extends Iterable { diff --git a/src/Main.java b/src/Main.java deleted file mode 100644 index 8f8f984..0000000 --- a/src/Main.java +++ /dev/null @@ -1,10 +0,0 @@ -//TIP To Run code, press or -// click the icon in the gutter. -public class Main { - public static void main(String[] args) { - //TIP Press with your caret at the highlighted text - // to see how IntelliJ IDEA suggests fixing it. - System.out.println("Hello and welcome!"); - - } -} \ No newline at end of file diff --git a/src/Queue/LinkedQueue.java b/src/Queue/LinkedQueue.java new file mode 100644 index 0000000..a7acfda --- /dev/null +++ b/src/Queue/LinkedQueue.java @@ -0,0 +1,215 @@ +package Queue; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Implementation of a Queue using a "list" of nodes and a Queue interface for generics + * + * @param Class may store various types of values + * @author Zalman I. + */ +public class LinkedQueue implements Queue { + /** + * A container which contains an item and a connection to another Node + */ + private class Node { + /** + * The item stored within the Node + */ + E item; + + /** + * The node this Node is pointing to + */ + Node next; + + /** + * Creates a node, and stores the given item within it + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + * + * @param item the item being stored in node + */ + public Node(E item) { + // store given item + this.item = item; + + // node starts off disconnected + next = null; + } + } + + /** + * The front of the queue (least recently added node) + */ + private Node front; + + /** + * The back of the queue (most recently added node) + */ + private Node back; + + /** + * The number of items stored in this stack + */ + private int size; + + /** + * Constructs an empty LinkedStack + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + */ + public LinkedQueue() { + // queue starts off empty + front = null; + back = null; + size = 0; + } + + /** + * Add an item to the queue. + * + * Runtime: O(1) as we can instantly add a new item to back of queue via the back variable, + * regardless of how many nodes exist in list. + * + * @param item the item to be added + */ + @Override + public void enqueue(E item) { + // track the item currently at back of queue + Node currBack = back; + + // replace back node with new node containing given item + back = new Node(item); + + // if the queue is empty + if(isEmpty()) { + // move back node to front + front = back; + } + + // if queue is not empty + else { + // add given item to end of queue + currBack.next = back; + } + + // account for new item in queue + size++; + } + + /** + * Remove an item from the queue. + * + * Runtime: O(1) as we can instantly access the front variable to retrieve item + * and overwrite it with the next node in queue. + * + * @return the item that was removed + */ + @Override + public E dequeue() { + // if queue contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot retrieve item from empty Queue"); + } + + // get requested item from node at front + E requestedItem = front.item; + + // overwrite current node at front with next in line + // if no more remain, front will become null + front = front.next; + + // in the event that queue is now empty and front is null, + // overwrite last item + if(isEmpty()) { + back = null; + } + + // account for removal of item from stack + size--; + + return requestedItem; + } + + /** + * Checks to see if the queue is empty. + * + * Runtime: O(1) as we are instantly accessing variables and checking a condition. + * This operation would always take the same runtime to conduct. + * + * @return true if the queue is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return size == 0 && front == null; + } + + /** + * Returns a count of the number of items in the queue. + * + * Runtime: O(1) as we are instantly retrieving a variable. + * This operation would always take the same runtime to conduct. + * + * @return the number of items in the queue + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new LinkedQueueIterator(); + } + + /** + * Implementation of an Iterator for the LinkedQueue class + */ + private class LinkedQueueIterator implements Iterator + { + /** + * The current Node being tracked by the Iterator + */ + private Node current; + + /** + * Constructs a LinkedQueue iterator, with the front node tracked first + */ + LinkedQueueIterator() { + current = front; + } + + /** + * Checks if list contains another element, and returns true/false accordingly + * @return true if list contains another element; otherwise false + */ + public boolean hasNext() { + return current != null; + } + + /** + * Gets and returns the start/front item in the list + * @return the start/front item in the list + */ + public E next() { + if(!hasNext()) { + throw new NoSuchElementException(); + } + + // get item at start/front of list + E currItem = current.item; + + // bring the next item over + current = current.next; + + return currItem; + } + } +} \ No newline at end of file diff --git a/src/Queue.java b/src/Queue/Queue.java similarity index 91% rename from src/Queue.java rename to src/Queue/Queue.java index ab5ca29..0dbc73b 100644 --- a/src/Queue.java +++ b/src/Queue/Queue.java @@ -1,5 +1,7 @@ +package Queue; + /** - * FIFO (first-in, first-out) Queue API + * FIFO (first-in, first-out) APIs.Queue API * @param class / data type of the items in the queue */ public interface Queue extends Iterable { diff --git a/src/Queue/QueueTestClient.java b/src/Queue/QueueTestClient.java new file mode 100644 index 0000000..06e0904 --- /dev/null +++ b/src/Queue/QueueTestClient.java @@ -0,0 +1,35 @@ +package Queue; + +import java.util.Scanner; + +public class QueueTestClient { + public static void main(String[] args) { + // setup storage queue + Queue storage = new LinkedQueue(); + + // setup scanner, taking in given string + Scanner line = new Scanner("to be or not to - be - - that - - - is"); + + // run through line + while (line.hasNext()) { + // get current item + String item = line.next(); + + // if the current item is not a dash + if (!item.equals("-")) { + // it is a word, add it to queue + storage.enqueue(item); + System.out.println(); + } + + // if it is a dash, and the stack is not empty + else if (!storage.isEmpty()) { + // get the item at front of queue, and display it + System.out.println(storage.dequeue()); + } + } + + // display how many items remain in queue at end of line + System.out.println("(" + storage.size() + " left in the queue)"); + } +} diff --git a/src/Stack/LinkedStack.java b/src/Stack/LinkedStack.java new file mode 100644 index 0000000..50e0519 --- /dev/null +++ b/src/Stack/LinkedStack.java @@ -0,0 +1,216 @@ +package Stack; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Implementation of a Stack using a "list" of nodes and a Stack interface for generics + * @param Class may store various types of values + * @author Zalman I. + */ +public class LinkedStack implements Stack { + /** + * A container which contains an item and a connection to another Node + */ + private class Node { + /** + * The item stored within the Node + */ + E item; + + /** + * The node this Node is pointing to + */ + Node next; + + /** + * Creates a node, and stores the given item within it + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + * + * @param item the item being stored in node + */ + public Node(E item) { + // store given item + this.item = item; + + // node starts off disconnected + next = null; + } + } + + /** + * The top of the stack (most recently added node) + */ + private Node top; + + /** + * The number of items stored in this stack + */ + private int size; + + /** + * Constructs an empty LinkedStack + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + */ + public LinkedStack() { + // stack starts off empty + top = null; + size = 0; + } + + /** + * Add an item to the stack. + * + * Runtime: O(1) as we can instantly add a new item to front/top via the top variable, + * regardless of how many nodes exist in stack. + * + * @param item the item to be added + */ + @Override + public void push(E item) { + // create new node containing given item + Node newNode = new Node(item); + + // if the stack is not empty + if(!isEmpty()) { + // point new node at top, so it isn't lost + newNode.next = top; + } + + // override top with newly created node + // (making new node first node in stack) + top = newNode; + + // account for new item in stack + size++; + } + + /** + * Removes the most recently added item from the stack. + * + * Runtime: O(1) as we can instantly access the top variable to retrieve item + * and overwrite it with the next node in stack. + * + * @return the item that was removed + */ + @Override + public E pop() { + // if stack contains no items, one cannot be removed + if(isEmpty()) { + throw new NoSuchElementException("Cannot retrieve item from empty Stack"); + } + + // get requested item from topmost node + E requestedItem = top.item; + + // overwrite top with node "under it", + // if no more remain, top will become null, making stack empty + top = top.next; + + // account for removal of item from stack + size--; + + return requestedItem; + } + + /** + * Returns the item at the top of the stack. + * Does not modify the stack or the item at the top. + * + * Runtime: O(1) as we can instantly access the top variable to retrieve item. + * + * @return item at the top of the stack. + */ + @Override + public E peek() { + // if buffer contains no items, one cannot be retrieved + if(isEmpty()) { + throw new NoSuchElementException("Cannot retrieve item from empty Stack"); + } + + // get and return item stored in topmost node + return top.item; + } + + /** + * Checks to see if the stack is empty. + * + * Runtime: O(1) as we are instantly accessing a variable and checking a condition. + * This operation would always take the same runtime to conduct. + * + * @return true if the stack is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return top == null && size == 0; + } + + /** + * Returns a count of the number of items in the stack. + * + * Runtime: O(1) as we are instantly retrieving a variable. + * This operation would always take the same runtime to conduct. + * + * @return the number of items in the stack + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new LinkedStackIterator(); + } + + /** + * Implementation of an Iterator for the LinkedStack class + */ + private class LinkedStackIterator implements Iterator + { + /** + * The current Node being tracked by the Iterator + */ + private Node current; + + /** + * Constructs a LinkedStack iterator, with the topmost node tracked first + */ + LinkedStackIterator() { + current = top; + } + + /** + * Checks if list contains another element, and returns true/false accordingly + * @return true if list contains another element; otherwise false + */ + public boolean hasNext() { + return current != null; + } + + /** + * Gets and returns the next/top item in the list + * @return the next/top item in the list + */ + public E next() { + if(!hasNext()) { + throw new NoSuchElementException(); + } + + // get item at end/top of list + E currItem = current.item; + + // move down to the next item + current = current.next; + + return currItem; + } + } +} \ No newline at end of file diff --git a/src/Stack/ResizingArrayStack.java b/src/Stack/ResizingArrayStack.java new file mode 100644 index 0000000..9f824a8 --- /dev/null +++ b/src/Stack/ResizingArrayStack.java @@ -0,0 +1,211 @@ +package Stack; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Implementation of a Stack using an array and a Stack interface for generics + * @param Class may store various types of values + * @author Zalman I. + */ +public class ResizingArrayStack implements Stack { + /** + * An array used to store items placed within the stack + */ + private E[] buffer; + + /** + * The number of items stored within buffer + */ + private int size; + + /** + * Constructs a ResizingArrayStack with an empty buffer, + * and a default max capacity of 10 items + * + * Runtime: O(1) as it always takes the same runtime to conduct this operation + */ + public ResizingArrayStack() { + // setup buffer with default max capacity of 10 + buffer = (E[]) new Object[10]; + + // buffer starts off empty + size = 0; + } + + /** + * Resize the buffer by updating its max capacity by given number + * + * Runtime: O(n) as it has to run through the buffer to copy over all items into a new array, + * therefore the runtime depends on the prior buffer's length + * + * @param maxCapacity the new max capacity of buffer + */ + private void resizeBuffer(int maxCapacity) { + // create a new buffer, with the given max capacity + E[] newBuffer = (E[]) new Object[maxCapacity]; + + // run through current buffer and copy over all items + for(int i = 0; i < size; i++) { + newBuffer[i] = buffer[i]; + } + + // override existing buffer with the newly created one, + // now with the requested max capacity + buffer = newBuffer; + } + + /** + * Add an item to the stack. + * + * Runtime: O(1) if buffer is empty/not full, as we are only accessing the final index to add an item. + * If the array is full O(n) as we need to run through buffer to copy over all items during resize. + * + * @param item the item to be added + */ + @Override + public void push(E item) { + // if the buffer is full, double its max capacity + if(size == buffer.length) { + resizeBuffer(buffer.length * 2); + } + + // add given item to "end/top" of buffer + buffer[size] = item; + + // account for new item being added + size++; + } + + /** + * Removes the most recently added item from the stack. + * + * Runtime: O(1) if buffer is not too large, as we are only accessing the final index to "pop off" an item. + * Otherwise, O(n) as we need to run through buffer to copy over all items during resize. + * + * @return the item that was removed + */ + @Override + public E pop() { + // if buffer contains no items, one cannot be retrieved + if(isEmpty()) { + throw new NoSuchElementException("Cannot retrieve item from empty Stack"); + } + + // get the end/top item from stack, account for index + E requestedItem = buffer[size - 1]; + + // clear that slot in buffer + buffer[size - 1] = null; + + // account for item being removed + size--; + + // if the buffer is not empty, and too large + if(size > 0 && size == buffer.length / 4) { + // reduce its current max capacity by half + resizeBuffer(buffer.length / 2); + } + + return requestedItem; + } + + /** + * Returns the item at the top of the stack. + * Does not modify the stack or the item at the top. + * + * Runtime: O(1) as we can instantly access the final index to retrieve item. + * + * @return item at the top of the stack. + */ + @Override + public E peek() { + // if buffer contains no items, one cannot be retrieved + if(isEmpty()) { + throw new NoSuchElementException("Cannot retrieve item from empty Stack"); + } + + // get and return end/top item in buffer + return buffer[size - 1]; + } + + /** + * Checks to see if the stack is empty. + * + * Runtime: O(1) as we are instantly accessing a variable and checking a condition. + * This operation would always take the same runtime to conduct. + * + * @return true if the stack is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns a count of the number of items in the stack. + * + * Runtime: O(1) as we are instantly retrieving a variable. + * This operation would always take the same runtime to conduct. + * + * @return the number of items in the stack + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new ReverseArrayStackIterator(); + } + + /** + * Implementation of an Iterator for the ReverseArrayStack class + */ + private class ReverseArrayStackIterator implements Iterator + { + /** + * The current number of items being tracked by iterator + */ + private int trackedSize; + + /** + * Constructs an ReverseArrayStackIterator iterator, with a tracker for buffer size + */ + ReverseArrayStackIterator() { + trackedSize = size; + } + + /** + * Checks if buffer has another element, and returns true/false accordingly + * @return true if buffer has another element; otherwise false + */ + public boolean hasNext() { + return trackedSize > 0; + } + + /** + * Gets and returns the next/top item in the buffer + * @return the next/top item in the buffer + */ + public E next() { + if(!hasNext()) { + throw new NoSuchElementException(); + } + + // get item at end/top of buffer + E currItem = buffer[trackedSize]; + + // move down to the next item + trackedSize--; + + return currItem; + } + } +} diff --git a/src/Stack.java b/src/Stack/Stack.java similarity index 93% rename from src/Stack.java rename to src/Stack/Stack.java index bb1000d..7d59c03 100644 --- a/src/Stack.java +++ b/src/Stack/Stack.java @@ -1,5 +1,7 @@ +package Stack; + /** - * Stack (LIFO: last-in, first-out) API + * APIs.Stack (LIFO: last-in, first-out) API * @param class / data type of the items in the stack */ public interface Stack extends Iterable { diff --git a/src/Stack/StackTestClient.java b/src/Stack/StackTestClient.java new file mode 100644 index 0000000..7cd74f1 --- /dev/null +++ b/src/Stack/StackTestClient.java @@ -0,0 +1,36 @@ +package Stack; + +import java.util.Scanner; + +public class StackTestClient { + public static void main(String[] args) { + // setup storage stack + //Stack storage = new ResizingArrayStack(); + Stack storage = new LinkedStack(); + + // setup scanner, taking in given string + Scanner line = new Scanner("to be or not to - be - - that - - - is"); + + // run through line + while (line.hasNext()) { + // get current item + String item = line.next(); + + // if the current item is not a dash + if (!item.equals("-")) { + // it is a word, add it to stack + storage.push(item); + System.out.println(); + } + + // if it is a dash, and the stack is not empty + else if (!storage.isEmpty()) { + // pop the topmost item off the stack, and display it + System.out.println(storage.pop()); + } + } + + // display how many items remain in stack at end of line + System.out.println("(" + storage.size() + " left on the stack)"); + } +} \ No newline at end of file diff --git a/tests/ArrayListTest.java b/tests/ArrayListTest.java new file mode 100644 index 0000000..c9ba03b --- /dev/null +++ b/tests/ArrayListTest.java @@ -0,0 +1,731 @@ +import List.ArrayList; +import org.junit.jupiter.api.Test; + +import java.util.NoSuchElementException; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; + +class ArrayListTest { + /** + * Create ArrayList at start for testing + */ + private final ArrayList testArrayList = new ArrayList(); + + /** + * The default max capacity of buffer, at creation + */ + private final int DEFAULT_BUFFER_LENGTH = 10; + + /** + * The first index in buffer is 0 + */ + private final int FIRST_INDEX = 0; + + /** + * The item returned by methods if item not found + */ + private final int INVALID_INDEX = -1; + + /** + * The standard filler item added to buffer prior to testing method + */ + private final int FILLER_ITEM = 5; + + /** + * The standard item used to test methods + */ + private final int TEST_ITEM = 20; + + @Test + void addFront_bufferContainsOneItem_addedSuccessfully() { + // add initial item + testArrayList.addBack(FILLER_ITEM); + + // add expected item to front + testArrayList.addFront(TEST_ITEM); + + // ensure expected item is at index 0 + assertEquals(TEST_ITEM, testArrayList.get(FIRST_INDEX)); + } + + @Test + void addFront_bufferContainsMultipleItems_addedSuccessfully() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // add expected item to front + testArrayList.addFront(TEST_ITEM); + + // ensure expected item is at index 0 + assertEquals(TEST_ITEM, testArrayList.get(FIRST_INDEX)); + } + + @Test + void addFront_bufferEmpty_addedSuccessfully() { + testArrayList.addFront(TEST_ITEM); + + // ensure expected item is at index 0 + assertEquals(TEST_ITEM, testArrayList.get(FIRST_INDEX)); + } + + @Test + void addFront_bufferFull_addedSuccessfully() { + // add 10 items to buffer + for(int i = 0; i < DEFAULT_BUFFER_LENGTH; i++) { + testArrayList.addBack(FILLER_ITEM); + } + + // add 11th item to front + testArrayList.addFront(TEST_ITEM); + + // ensure expected item is at index 0 + assertEquals(TEST_ITEM, testArrayList.get(FIRST_INDEX)); + + } + + @Test + void addBack_bufferContainsOneItem_addedSuccessfully() { + // add initial item + testArrayList.addFront(FILLER_ITEM); + + // add expected item to back + testArrayList.addBack(TEST_ITEM); + + // ensure expected item is at final index + assertEquals(TEST_ITEM, testArrayList.get(testArrayList.size() - 1)); + } + + @Test + void addBack_bufferContainsMultipleItems_addedSuccessfully() { + // add several initial items + testArrayList.addFront(FILLER_ITEM); + testArrayList.addFront(FILLER_ITEM); + testArrayList.addFront(FILLER_ITEM); + + // add expected item to back + testArrayList.addBack(TEST_ITEM); + + // ensure expected item is at final index + assertEquals(TEST_ITEM, testArrayList.get(testArrayList.size() - 1)); + } + + @Test + void addBack_bufferEmpty_addedSuccessfully() { + testArrayList.addBack(TEST_ITEM); + + // ensure the expected item is at final index + assertEquals(TEST_ITEM, testArrayList.get(testArrayList.size() - 1)); + } + + @Test + void addBack_bufferFull_addedSuccessfully() { + // add 10 items to buffer + for(int i = 0; i < DEFAULT_BUFFER_LENGTH; i++) { + testArrayList.addFront(FILLER_ITEM); + } + + // add 11th item to back + testArrayList.addBack(TEST_ITEM); + + // ensure expected item is at final index + assertEquals(TEST_ITEM, testArrayList.get(testArrayList.size() - 1)); + } + + @Test + void add_bufferContainsOneItem_addedSuccessfully() { + // add initial item + testArrayList.addBack(FILLER_ITEM); + + // add expected item to buffer + testArrayList.add(1, TEST_ITEM); + + // ensure expected item is at final index + assertEquals(TEST_ITEM, testArrayList.get(testArrayList.size() - 1)); + } + + @Test + void add_bufferContainsMultipleItems_addedSuccessfully() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // add expected item somewhere in buffer + testArrayList.add(2, TEST_ITEM); + + // ensure expected item is at middle index + assertEquals(TEST_ITEM, testArrayList.get(2)); + } + + @Test + void add_bufferEmpty_addedSuccessfully() { + testArrayList.add(0, TEST_ITEM); + + // ensure the expected item is at final index + assertEquals(TEST_ITEM, testArrayList.get(testArrayList.size() - 1)); + } + + @Test + void add_bufferFull_addedSuccessfully() { + // add 10 items to buffer + for(int i = 0; i < DEFAULT_BUFFER_LENGTH; i++) { + testArrayList.addBack(FILLER_ITEM); + } + + // add 11th item to buffer + testArrayList.add(2, TEST_ITEM); + + // ensure expected item is at final index + assertEquals(TEST_ITEM, testArrayList.get(2)); + } + + @Test + void add_invalidIndexNegative_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to add item at invalid index + testArrayList.add(-1, TEST_ITEM); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void add_invalidIndexMoreThanSize_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to add item at invalid index + testArrayList.add(1, TEST_ITEM); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void get_bufferContainsOneItem_returnsItem() { + // add expected item to buffer + testArrayList.addFront(TEST_ITEM); + + // attempt to retrieve expected item + assertEquals(TEST_ITEM, testArrayList.get(FIRST_INDEX)); + } + + @Test + void get_bufferContainsMultipleItems_returnItem() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // add item to retrieve + testArrayList.addBack(TEST_ITEM); + + // attempt to retrieve expected item + assertEquals(TEST_ITEM, testArrayList.get(testArrayList.size() - 1)); + } + + @Test + void get_bufferEmpty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to get item from empty buffer + testArrayList.get(FIRST_INDEX); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void get_invalidIndexNegative_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to get item from invalid index + testArrayList.get(-1); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void get_invalidIndexMoreThanSize_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to get item from invalid index + testArrayList.get(1); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void set_bufferContainsOneItem_setItemAtIndex() { + // add initial item to buffer + testArrayList.addFront(FILLER_ITEM); + + // replace item at that index + testArrayList.set(FIRST_INDEX, TEST_ITEM); + + // attempt to retrieve expected item + assertEquals(TEST_ITEM, testArrayList.get(FIRST_INDEX)); + } + + @Test + void set_bufferContainsMultipleItems_setItemAtIndex() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // replace item at second index + testArrayList.set(2, TEST_ITEM); + + // attempt to retrieve expected item + assertEquals(TEST_ITEM, testArrayList.get(2)); + } + + @Test + void set_bufferEmpty_setItemAtIndex() { + // add item to index 0 of empty buffer + testArrayList.set(FIRST_INDEX, TEST_ITEM); + + // check if exception was thrown + assertEquals(TEST_ITEM, testArrayList.get(FIRST_INDEX)); + } + + @Test + void set_invalidIndexNegative_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to set item at invalid index + testArrayList.set(-1, TEST_ITEM); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void set_invalidIndexMoreThanSize_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to set item at invalid index + testArrayList.set(1, TEST_ITEM); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeFront_bufferContainsOneItem_removedSuccessfully() { + // add item to remove + testArrayList.addFront(TEST_ITEM); + + // attempt to remove first item from buffer + assertEquals(TEST_ITEM, testArrayList.removeFront()); + + // ensure buffer is now empty + assertTrue(testArrayList.isEmpty()); + } + + @Test + void removeFront_bufferContainsMultipleItems_removedSuccessfully() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // add item to remove + testArrayList.addFront(TEST_ITEM); + + // attempt to remove first item from buffer + assertEquals(TEST_ITEM, testArrayList.removeFront()); + + // ensure item was removed from buffer + assertNotEquals(TEST_ITEM, testArrayList.get(FIRST_INDEX)); + assertEquals(3, testArrayList.size()); + } + + @Test + void removeFront_bufferEmpty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove item at index 0 + testArrayList.removeFront(); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeBack_bufferContainsOneItem_removedSuccessfully() { + // add item to remove + testArrayList.addFront(TEST_ITEM); + + // attempt to remove last item from buffer + assertEquals(TEST_ITEM, testArrayList.removeBack()); + + // ensure buffer is now empty + assertTrue(testArrayList.isEmpty()); + } + + @Test + void removeBack_bufferContainsMultipleItems_removedSuccessfully() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // add item to remove + testArrayList.addBack(TEST_ITEM); + + // attempt to remove back item from buffer + assertEquals(TEST_ITEM, testArrayList.removeBack()); + + // ensure item was removed from buffer + assertNotEquals(TEST_ITEM, testArrayList.get(testArrayList.size())); + assertEquals(3, testArrayList.size()); + } + + @Test + void removeBack_bufferEmpty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove item at index 0 + testArrayList.removeBack(); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeItem_bufferContainsOneItem_removedSuccessfully() { + // add item to remove + testArrayList.addBack(TEST_ITEM); + + // attempt to remove item from buffer + testArrayList.remove((Integer) TEST_ITEM); + + // ensure buffer is now empty + assertTrue(testArrayList.isEmpty()); + } + + @Test + void removeItem_bufferContainsMultipleItems_removedSuccessfully() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // add item to remove + testArrayList.add(2, TEST_ITEM); + + // attempt to remove item from buffer + testArrayList.remove((Integer) TEST_ITEM); + + // ensure item was removed from buffer + assertNotEquals(TEST_ITEM, testArrayList.get(2)); + assertEquals(3, testArrayList.size()); + } + + @Test + void removeItem_bufferEmpty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove item from empty buffer + testArrayList.remove((Integer) TEST_ITEM); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeItem_itemNotInBuffer_throwsException() { + // setup flag + boolean exceptionThrown = false; + + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + try { + // attempt to remove nonexistent item from buffer + testArrayList.remove((Integer) TEST_ITEM); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeIndex_bufferContainsOneItem_removedSuccessfully() { + // add item to remove + testArrayList.addBack(TEST_ITEM); + + // attempt to remove item from buffer + assertEquals(TEST_ITEM, testArrayList.remove(FIRST_INDEX)); + + // ensure buffer is now empty + assertTrue(testArrayList.isEmpty()); + } + + @Test + void removeIndex_bufferContainsMultipleItems_removedSuccessfully() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // add item to remove + testArrayList.add(2, TEST_ITEM); + + // attempt to remove item from buffer + assertEquals(TEST_ITEM, testArrayList.remove(2)); + + // ensure item was removed from buffer + assertEquals(3, testArrayList.size()); + } + + @Test + void removeIndex_bufferEmpty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove item at index 0 + testArrayList.remove(FIRST_INDEX); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeIndex_invalidIndexNegative_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove item at invalid index + testArrayList.remove(-1); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeIndex_invalidIndexMoreThanSize_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove item at invalid index + testArrayList.remove(1); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void contains_itemExists_returnsTrue() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // add item to check for + testArrayList.addBack(TEST_ITEM); + + // check if item is in buffer + assertTrue(testArrayList.contains(TEST_ITEM)); + } + + @Test + void contains_itemNotExists_returnsFalse() { + // add several initial items + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // check if item is in buffer + assertFalse(testArrayList.contains(TEST_ITEM)); + } + + @Test + void contains_bufferEmpty_returnsFalse() { + assertFalse(testArrayList.contains(TEST_ITEM)); + } + + @Test + void contains_bufferFullItemExists_returnsTrue() { + // add 9 items to buffer + for(int i = 0; i < DEFAULT_BUFFER_LENGTH - 1; i++) { + testArrayList.addBack(FILLER_ITEM); + } + + // add test item as last item + testArrayList.addBack(TEST_ITEM); + + // check if item is in buffer + assertTrue(testArrayList.contains(TEST_ITEM)); + } + + @Test + void isEmpty_bufferContainsOneItem_returnsFalse() { + // add item so the buffer is not empty + testArrayList.addBack(FILLER_ITEM); + + assertFalse(testArrayList.isEmpty()); + } + + @Test + void isEmpty_bufferContainsMultipleItems_returnsFalse() { + // add items so the buffer is not empty + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + // check if buffer is empty + assertFalse(testArrayList.isEmpty()); + } + + @Test + void isEmpty_bufferFull_returnsFalse() { + // add 10 items to buffer + for(int i = 0; i < DEFAULT_BUFFER_LENGTH; i++) { + testArrayList.addBack(FILLER_ITEM); + } + + // check if buffer is empty + assertFalse(testArrayList.isEmpty()); + } + + @Test + void isEmpty_bufferEmpty_returnsTrue() { + // check if buffer is empty + assertTrue(testArrayList.isEmpty()); + } + + @Test + void size_bufferContainsOneItem_returnsSize() { + // add item so the buffer is not empty + testArrayList.addBack(FILLER_ITEM); + + assertEquals(1, testArrayList.size()); + } + + @Test + void size_bufferContainsMultipleItems_returnSize() { + // add items so the buffer is not empty + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + testArrayList.addBack(FILLER_ITEM); + + assertEquals(3, testArrayList.size()); + } + + @Test + void size_bufferEmpty_returnSize() { + assertEquals(0, testArrayList.size()); + } + + @Test + void size_bufferFull_returnSize() { + // add 10 items to buffer + for(int i = 0; i < DEFAULT_BUFFER_LENGTH; i++) { + testArrayList.addBack(FILLER_ITEM); + } + + assertEquals(DEFAULT_BUFFER_LENGTH, testArrayList.size()); + } +} \ No newline at end of file diff --git a/tests/LinkedListTest.java b/tests/LinkedListTest.java new file mode 100644 index 0000000..ddde826 --- /dev/null +++ b/tests/LinkedListTest.java @@ -0,0 +1,652 @@ +import List.LinkedList; +import org.junit.jupiter.api.Test; + +import java.util.NoSuchElementException; + +import static org.junit.jupiter.api.Assertions.*; + +class LinkedListTest { + /** + * Create LinkedList at start for testing + */ + private final LinkedList testLinkedList = new LinkedList(); + + /** + * The first index in list is 0 + */ + private final int FIRST_INDEX = 0; + + /** + * The standard filler item added to container prior to testing method + */ + private final int FILLER_ITEM = 5; + + /** + * The standard item used to test methods + */ + private final int TEST_ITEM = 20; + + /** + * Adds ten items to list for testing + */ + private void addMultipleItems() { + // add 10 items to list + for(int i = 0; i < 10; i++) { + testLinkedList.addBack(FILLER_ITEM); + } + } + + @Test + void addFront_hasItem_addedSuccessfully() { + // add initial item + testLinkedList.addBack(FILLER_ITEM); + + // add test item + testLinkedList.addFront(TEST_ITEM); + + // ensure expected item is at index 0 + assertEquals(TEST_ITEM, testLinkedList.get(FIRST_INDEX)); + } + + @Test + void addFront_hasMultipleItems_addedSuccessfully() { + // add several initial items + addMultipleItems(); + + // add test item + testLinkedList.addFront(TEST_ITEM); + + // ensure expected item is at index 0 + assertEquals(TEST_ITEM, testLinkedList.get(FIRST_INDEX)); + } + + @Test + void addFront_empty_addedSuccessfully() { + // make test item new head + testLinkedList.addFront(TEST_ITEM); + + // ensure expected item is at index 0 + assertEquals(TEST_ITEM, testLinkedList.get(FIRST_INDEX)); + } + + @Test + void addBack_hasItem_addedSuccessfully() { + // add initial item + testLinkedList.addFront(FILLER_ITEM); + + // add test item + testLinkedList.addBack(TEST_ITEM); + + // ensure expected item is at end of list + assertEquals(TEST_ITEM, testLinkedList.get(testLinkedList.size() -1)); + } + + @Test + void addBack_hasMultipleItems_addedSuccessfully() { + // add several initial items + addMultipleItems(); + + // add test item + testLinkedList.addBack(TEST_ITEM); + + // ensure expected item is at end of list + assertEquals(TEST_ITEM, testLinkedList.get(testLinkedList.size() -1)); + } + + @Test + void addBack_empty_addedSuccessfully() { + // make test item new tail + testLinkedList.addBack(TEST_ITEM); + + // ensure expected item is at end of list + assertEquals(TEST_ITEM, testLinkedList.get(testLinkedList.size() -1)); + } + + @Test + void add_hasItem_addedSuccessfully() { + // add initial item + testLinkedList.addFront(FILLER_ITEM); + + // add test item + testLinkedList.add(testLinkedList.size(), TEST_ITEM); + + // ensure expected item is at expected index + assertEquals(TEST_ITEM, testLinkedList.get(testLinkedList.size() - 1)); + } + + @Test + void add_hasMultipleItems_addedSuccessfully() { + // add several initial items + addMultipleItems(); + + // add test item + testLinkedList.add(4, TEST_ITEM); + + // ensure expected item is at expected index + assertEquals(TEST_ITEM, testLinkedList.get(4)); + } + + @Test + void add_empty_addedSuccessfully() { + // add test item to list + testLinkedList.add(FIRST_INDEX, TEST_ITEM); + + // ensure expected item is in list + assertEquals(TEST_ITEM, testLinkedList.get(FIRST_INDEX)); + } + + @Test + void add_invalidIndexNegative_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to add item at invalid index + testLinkedList.add(FIRST_INDEX - 1, TEST_ITEM); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void add_invalidIndexMoreThanSize_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to add item at invalid index + testLinkedList.add(FIRST_INDEX + 1, TEST_ITEM); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void get_hasItem_returnsItem() { + // add expected item to list + testLinkedList.addFront(TEST_ITEM); + + // attempt to retrieve expected item + assertEquals(TEST_ITEM, testLinkedList.get(FIRST_INDEX)); + } + + @Test + void get_hasMultipleItems_returnsItem() { + // add several initial items + addMultipleItems(); + + // add item to retrieve + testLinkedList.addBack(TEST_ITEM); + + // attempt to retrieve expected item at final index + assertEquals(TEST_ITEM, testLinkedList.get(testLinkedList.size() - 1)); + } + + @Test + void get_listEmpty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to get item from empty list + testLinkedList.get(FIRST_INDEX); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void get_invalidIndexNegative_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to get item from invalid index + testLinkedList.get(FIRST_INDEX - 1); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void get_invalidIndexMoreThanSize_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to get item from invalid index + testLinkedList.get(FIRST_INDEX + 1); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void set_hasItem_setItemAtIndex() { + // add initial item to list + testLinkedList.addFront(FILLER_ITEM); + + // replace item at that index + testLinkedList.set(FIRST_INDEX, TEST_ITEM); + + // attempt to retrieve expected item + assertEquals(TEST_ITEM, testLinkedList.get(FIRST_INDEX)); + } + + @Test + void set_hasMultipleItems_setItemAtIndex() { + // add several initial items + addMultipleItems(); + + // replace item at sixth index + testLinkedList.set(6, TEST_ITEM); + + // attempt to retrieve expected item + assertEquals(TEST_ITEM, testLinkedList.get(6)); + } + + @Test + void set_empty_setItemAtIndex() { + // add item to index 0 of empty list + testLinkedList.set(FIRST_INDEX, TEST_ITEM); + + // attempt to retrieve expected item + assertEquals(TEST_ITEM, testLinkedList.get(FIRST_INDEX)); + + // ensure size tracker was updated + assertEquals(1, testLinkedList.size()); + } + + @Test + void set_invalidIndexNegative_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to set item at invalid index + testLinkedList.set(FIRST_INDEX - 1, TEST_ITEM); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void set_invalidIndexMoreThanSize_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to set item at invalid index + testLinkedList.set(FIRST_INDEX + 1, TEST_ITEM); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeFront_hasItem_removedSuccessfully() { + // add item to remove + testLinkedList.addFront(TEST_ITEM); + + // attempt to remove item from list + assertEquals(TEST_ITEM, testLinkedList.removeFront()); + + // ensure list is now empty + assertTrue(testLinkedList.isEmpty()); + } + + @Test + void removeFront_hasMultipleItems_removedSuccessfully() { + // add several initial items + addMultipleItems(); + + // add item to remove + testLinkedList.addFront(TEST_ITEM); + + // attempt to remove front item from list + testLinkedList.removeFront(); + + // ensure item was removed from list + assertNotEquals(TEST_ITEM, testLinkedList.get(FIRST_INDEX)); + assertFalse(testLinkedList.contains(TEST_ITEM)); + assertEquals(10, testLinkedList.size()); + } + + @Test + void removeFront_empty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove nonexistent item + testLinkedList.removeFront(); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeBack_hasItem_removedSuccessfully() { + // add item to remove + testLinkedList.addBack(TEST_ITEM); + + // attempt to remove item from list + testLinkedList.removeFront(); + + // ensure list is now empty + assertTrue(testLinkedList.isEmpty()); + } + + @Test + void removeBack_hasMultipleItems_removedSuccessfully() { + // add several initial items + addMultipleItems(); + + // add item to remove + testLinkedList.addBack(TEST_ITEM); + + // attempt to remove front item from list + testLinkedList.removeBack(); + + // ensure item was removed from list + assertNotEquals(TEST_ITEM, testLinkedList.get(testLinkedList.size() - 1)); + assertFalse(testLinkedList.contains(TEST_ITEM)); + assertEquals(10, testLinkedList.size()); + } + + @Test + void removeBack_empty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove nonexistent item + testLinkedList.removeBack(); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + // + + @Test + void removeItem_hasItem_removedSuccessfully() { + // add item to remove + testLinkedList.addBack(TEST_ITEM); + + // attempt to remove item from list + testLinkedList.remove((Integer) TEST_ITEM); + + // ensure list is now empty + assertTrue(testLinkedList.isEmpty()); + } + + @Test + void removeItem_hasMultipleItems_removedSuccessfully() { + // add several initial items + addMultipleItems(); + + // add item to remove + testLinkedList.add(9, TEST_ITEM); + + // attempt to remove item from list + testLinkedList.remove((Integer) TEST_ITEM); + + // ensure item was removed from list + assertNotEquals(TEST_ITEM, testLinkedList.get(9)); + assertFalse(testLinkedList.contains(TEST_ITEM)); + assertEquals(10, testLinkedList.size()); + } + + @Test + void removeItem_empty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove item from empty list + testLinkedList.remove((Integer) TEST_ITEM); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeItem_itemNotExists_throwsException() { + // setup flag + boolean exceptionThrown = false; + + // add several initial items + addMultipleItems(); + + try { + // attempt to remove nonexistent item from list + testLinkedList.remove((Integer) TEST_ITEM); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeIndex_hasItem_removedSuccessfully() { + // add item to remove + testLinkedList.addBack(TEST_ITEM); + + // attempt to remove item from list + assertEquals(TEST_ITEM, testLinkedList.remove(FIRST_INDEX)); + + // ensure list is now empty + assertTrue(testLinkedList.isEmpty()); + } + + @Test + void removeIndex_removeItemFromMiddle_removedSuccessfully() { + // add several initial items + addMultipleItems(); + + // add item to remove + testLinkedList.add(7, TEST_ITEM); + + // attempt to remove item from list + assertEquals(TEST_ITEM, testLinkedList.remove(7)); + + // ensure item was removed from list + assertFalse(testLinkedList.contains(TEST_ITEM)); + assertEquals(10, testLinkedList.size()); + } + + @Test + void removeIndex_removeItemFromEnd_removedSuccessfully() { + // add several initial items + addMultipleItems(); + + // add item to remove + testLinkedList.add(testLinkedList.size(), TEST_ITEM); + + // attempt to remove item from list + assertEquals(TEST_ITEM, testLinkedList.remove(testLinkedList.size())); + + // ensure item was removed from list + assertFalse(testLinkedList.contains(TEST_ITEM)); + assertEquals(10, testLinkedList.size()); + } + + @Test + void removeIndex_empty_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove nonexistent item + testLinkedList.remove(FIRST_INDEX); + } + + catch (NoSuchElementException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeIndex_invalidIndexNegative_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove item at invalid index + testLinkedList.remove(FIRST_INDEX - 1); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void removeIndex_invalidIndexMoreThanSize_throwsException() { + // setup flag + boolean exceptionThrown = false; + + try { + // attempt to remove item at invalid index + testLinkedList.remove(FIRST_INDEX + 1); + } + + catch (IndexOutOfBoundsException e) { + exceptionThrown = true; + } + + // check if exception was thrown + assertTrue(exceptionThrown); + } + + @Test + void contains_itemExists_returnsTrue() { + // add several initial items + addMultipleItems(); + + // add item to check for + testLinkedList.addBack(TEST_ITEM); + + // check if item is in list + assertTrue(testLinkedList.contains(TEST_ITEM)); + } + + @Test + void contains_itemNotExists_returnsFalse() { + // add several initial items + addMultipleItems(); + + // check if item is in list + assertFalse(testLinkedList.contains(TEST_ITEM)); + } + + @Test + void contains_empty_returnsFalse() { + assertFalse(testLinkedList.contains(TEST_ITEM)); + } + + @Test + void isEmpty_hasItem_returnsFalse() { + // add item so the list is not empty + testLinkedList.addFront(FILLER_ITEM); + + assertFalse(testLinkedList.isEmpty()); + } + + @Test + void isEmpty_hasMultipleItems_returnsFalse() { + // add items so list is not empty + addMultipleItems(); + + // check if list is empty + assertFalse(testLinkedList.isEmpty()); + } + + @Test + void isEmpty_empty_returnsTrue() { + // check if list is empty + assertTrue(testLinkedList.isEmpty()); + } + + @Test + void size_hasItem_returnsSize() { + // add item so list is not empty + testLinkedList.addFront(FILLER_ITEM); + + assertEquals(1, testLinkedList.size()); + } + + @Test + void size_hasMultipleItems_returnsSize() { + // add items so the list is not empty + addMultipleItems(); + + assertEquals(10, testLinkedList.size()); + } + + @Test + void size_empty_returnsSize() { + assertEquals(0, testLinkedList.size()); + } +} \ No newline at end of file