diff --git a/.idea/misc.xml b/.idea/misc.xml index 6f29fee..5c02e7d 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SDEV333-Term-Project.iml b/SDEV333-Term-Project.iml index c90834f..1ad1435 100644 --- a/SDEV333-Term-Project.iml +++ b/SDEV333-Term-Project.iml @@ -3,9 +3,26 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/ArrayListTest.java b/Tests/ArrayListTest.java new file mode 100644 index 0000000..586ff15 --- /dev/null +++ b/Tests/ArrayListTest.java @@ -0,0 +1,186 @@ +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ArrayListTest { + ArrayList testList = new ArrayList<>(); + + @Test + void addFront() { + //catches empty array when a get is used to verify it returns the correct error. + try { + testList.get(0); + fail(); + } catch (Exception e) { + final String expected = "Index cannot be outside the size of the array."; + assertEquals(expected, e.getMessage()); + } + Integer one = 1; + Integer two = 2; + String three = "three"; + assertEquals(0, testList.size()); + testList.addFront((T)one); + assertEquals(1, testList.get(0)); + testList.addFront((T)two); + assertEquals(2, testList.get(0)); + testList.addFront((T)three); + assertEquals("three", testList.get(0)); + assertEquals(3, testList.size()); + } + + @Test + void addBack() { + assertEquals(0, testList.size()); + testList.addBack((T)(Integer)2); + assertEquals(2, testList.get(testList.size() - 1)); + testList.addBack((T) "777"); + assertEquals("777", testList.get(testList.size() - 1)); + assertEquals(2, testList.size()); + } + + @Test + void add() { + + //catches an attempt to add a value outside the size of the array + try { + testList.add(-1,(T)"1"); + fail(); + } catch (Exception e) { + final String expected = "Index ouf of bounds. NOPE!"; + assertEquals(expected, e.getMessage()); + } + assertEquals(0, testList.size()); + testList.addFront((T)(Integer)3); + for(int i = 0; i < 7; i++) { + testList.add(i, (T)(Integer)((i+1)*2)); + } + assertEquals(2, testList.get(0)); + testList.add(7,(T)(Integer)66); + assertEquals(66, testList.get(7)); + assertEquals(9, testList.size()); + testList.add(8,(T)"Found"); + assertEquals("Found", testList.get(8)); + assertEquals(3, testList.get(9)); + assertEquals(10, testList.size()); + } + + @Test + void get() { + //catches empty array when a get is used to verify it returns the correct error. + try { + testList.get(0); + fail(); + } catch (Exception e) { + final String expected = "Index cannot be outside the size of the array."; + assertEquals(expected, e.getMessage()); + } + for(int i = 0; i < 5; i++){ + testList.addFront((T)(Integer)i); + } + assertEquals(4, testList.get(0)); + assertEquals(3, testList.get(1)); + assertEquals(2, testList.get(2)); + assertEquals(1, testList.get(3)); + assertEquals(0, testList.get(4)); + testList.addBack((T)"First Value"); + assertEquals("First Value", testList.get(testList.size()-1)); + } + + @Test + void set() { + for(int i=0; i<4; i++) { + testList.addFront((T)(Integer)i); + } + assertEquals(0, testList.get(3)); + testList.set(3, (T)(Integer)1); + assertEquals(1, testList.get(3)); + try { + testList.set(7, (T)(Integer)99); + fail(); + } catch (Exception e) { + final String expected = "Index cannot be outside the size of the array."; + assertEquals(expected, e.getMessage()); + } + } + + @Test + void removeFront() { + testList.addFront((T)"First Added"); + testList.addBack((T)"Second Value"); + assertEquals("First Added", testList.get(0)); + assertEquals("First Added", testList.removeFront()); + assertEquals("Second Value", testList.get(0)); + } + + @Test + void removeBack() { + testList.addFront((T)"First Added"); + testList.addBack((T)"Second Value"); + assertEquals("First Added", testList.get(0)); + assertEquals("Second Value", testList.get(1)); + assertEquals("Second Value", testList.removeBack()); + assertEquals("First Added", testList.get(0)); + } + + @Test + void remove() { + testList.addFront((T)"First Added"); + testList.addBack((T)"Second Value"); + testList.add(1, (T)"Middle Value"); + assertEquals(3, testList.size()); + testList.remove((T)"Middle Value"); + assertEquals(2, testList.size()); + assertEquals("Second Value", testList.get(1)); + assertEquals("[First Added, Second Value]", testList.toString()); + } + + @Test + void testRemove() { + try { + testList.remove(7); + fail(); + } catch (Exception e) { + final String expected = "Index out of bounds at position "+7; + assertEquals(expected, e.getMessage()); + } + testList.addFront((T)"First Added"); + testList.addBack((T)"Second Value"); + testList.add(1, (T)"Middle Value"); + assertEquals(3, testList.size()); + assertEquals("Second Value", testList.remove(2)); + assertEquals(2, testList.size()); + assertEquals("[First Added, Middle Value]", testList.toString()); + } + + @Test + void contains() { + testList.addFront((T)"First Added"); + testList.addBack((T)"Second Value"); + testList.add(1, (T)"Middle Value"); + assertTrue(testList.contains((T)"Second Value")); + assertFalse(testList.contains((T)"Last Value")); + } + + @Test + void isEmpty() { + assertTrue(testList.isEmpty()); + testList.addFront((T)"First Added"); + assertFalse(testList.isEmpty()); + testList.remove((T)"First Added"); + assertTrue(testList.isEmpty()); + } + + @Test + void size() { + assertEquals(0, testList.size()); + testList.addFront((T)(Character)'x'); + assertEquals(1, testList.size()); + } + + @Test + void testToString() { + testList.addFront((T)"This is a String "); + testList.addBack((T)(Integer)7); + assertEquals("[This is a String , 7]", testList.toString()); + } +} \ No newline at end of file diff --git a/Tests/LinkedListTest.java b/Tests/LinkedListTest.java new file mode 100644 index 0000000..372bc76 --- /dev/null +++ b/Tests/LinkedListTest.java @@ -0,0 +1,167 @@ +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class LinkedListTest { + LinkedList testList = new LinkedList<>(); + + @Test + void addFront() { + //catches empty array when a get is used to verify it returns the correct error. + try { + testList.get(0); + fail(); + } catch (Exception e) { + final String expected = "The list is empty"; + assertEquals(expected, e.getMessage()); + } + testList.addFront((E) "Three"); + assertEquals("Three", testList.get(0)); + testList.addFront((E) (Double) 3.14159); + assertEquals(3.14159, testList.get(0)); + assertEquals(2, testList.size()); + } + + @Test + void addBack() { + testList.addBack((E) "4"); + testList.addBack((E) (Integer) 7); + assertEquals(7, testList.get(testList.size() - 1)); + } + + @Test + void add() { + + //catches an attempt to add a value outside the size of the array + try { + testList.add(77, (E) (Integer) 1); + fail(); + } catch (Exception e) { + final String expected = "Index out of bounds"; + assertEquals(expected, e.getMessage()); + } + + testList.addFront((E) (Integer) 3); + for (int i = 0; i < 7; i++) { + testList.add(i, (E) (Double) ((i + 1) * 2.1)); + } + assertEquals(2.1, testList.get(0)); + assertSame(testList.get(7),3); + testList.add(7, (E) (Integer) 66); + assertEquals(66, testList.get(7)); + } + + @Test + void get() { + //catches empty array when a get is used to verify it returns the correct error. + try { + testList.get(0); + fail(); + } catch (Exception e) { + final String expected = "The list is empty"; + assertEquals(expected, e.getMessage()); + } + for(int i = 0; i < 5; i++){ + testList.addFront((E)(Integer)i); + } + assertEquals(4, testList.get(0)); + assertEquals(3, testList.get(1)); + assertEquals(2, testList.get(2)); + assertEquals(1, testList.get(3)); + assertEquals(0, testList.get(4)); + } + + @Test + void set() { + } + + @Test + void removeFront() { + //catches empty array when an attempt to remove the value from the front of an empty array is made + try { + testList.removeFront(); + fail(); + } catch (Exception e) { + final String expected = "The list is empty"; + assertEquals(expected, e.getMessage()); + } + testList.addFront((E)(Integer)3); + testList.addFront((E)(Integer)4); + testList.removeFront(); + assertEquals(3, testList.get(0)); + } + + @Test + void removeBack() { + //catches empty array when an attempt to remove the value from the back of an empty array is made + try { + testList.removeBack(); + fail(); + } catch (Exception e) { + final String expected = "The list is empty"; + assertEquals(expected, e.getMessage()); + } + testList.addFront((E)(Integer)11); + testList.addBack((E)(Integer)12); + testList.removeBack(); + assertEquals(11, testList.get(testList.size() - 1)); + } + + @Test + void remove() { + //catches empty array when an attempt to remove an element from an empty array is made + try { + testList.remove(7); + fail(); + } catch (Exception e) { + final String expected = "Index out of bounds"; + assertEquals(expected, e.getMessage()); + } + testList.addFront((E)(Integer)99); + testList.remove(0); + assertEquals(0, testList.size()); + + for(int i = 0; i < 5; i++){ + testList.addFront((E)(Integer)i); + } + testList.remove(1); + assertEquals(4, testList.get(0)); + assertEquals(2, testList.get(1)); + assertEquals(1, testList.get(2)); + assertEquals(0, testList.get(3)); + } + + @Test + void testRemove() { + assertFalse(testList.contains((E)(Integer)2)); + for(int i = 5; i < 10; i++){ + testList.addFront((E)(Integer)i); + } + assertTrue(testList.contains((E)(Integer)6)); + assertTrue(testList.contains((E)(Integer)8)); + assertFalse(testList.contains((E)(Integer)10)); + assertFalse(testList.contains((E)(Integer)(-10))); + } + + @Test + void contains() { + } + + @Test + void isEmpty() { + assertTrue(testList.isEmpty()); + testList.addFront((E)(Integer)2); + assertFalse(testList.isEmpty()); + } + + @Test + void size() { + assertEquals(0, testList.size()); + testList.addFront((E)(Integer)1); + assertEquals(1, testList.size()); + for(int i = 0; i < 5; i++){ + testList.addFront((E)(Integer)i); + } + assertEquals(6, testList.size()); + } +} \ No newline at end of file diff --git a/src/ArrayList.java b/src/ArrayList.java new file mode 100644 index 0000000..1df9e07 --- /dev/null +++ b/src/ArrayList.java @@ -0,0 +1,371 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Spliterator; +import java.util.function.Consumer; + +/** + * Implementation of the ArrayList using the List interface. This is my term assignment 1 Linked List. + * + * @param class / data type of the items in the ArrayList + * @author Rob Smith + * @version 1.0 + */ +public class ArrayList implements List { + + private int size; + private E[] buffer; + + /** + * Constructor for the ArrayList<> class. + * Runtime is O(1). It always takes the same time to perform this construction. + */ + public ArrayList() { + this.size = 0; + this.buffer = (E[])new Object[10]; + } + + /** + * Add item to the front. + * Runtime is O(n) if it doesn't need to resize. The method loops the through the array one time. + * If it needs to resize the runtime is O(n)+runtime of doubleSize() which is O(1) + the runtime of resize which + * is O(n). The total time if a resize is triggered is still O(n) but it has a higher constant. + * + * @param item the item to be added + */ + @Override + public void addFront(E item) { + doubleSize(); + for (int i = size; i >= 1; i--) { + buffer[i] = buffer[i - 1]; + } + buffer[0] = item; + size++; + } + + /** + * Add item to the back. + * Runtime for this is O(1) if it doesn't need to resize. It always takes the same time to add to the back of the array. + * If a resize is triggered the runtime is O(n). + * + * @param item the item to be added + */ + @Override + public void addBack(E item) { + doubleSize(); + buffer[size] = item; + size++; + } + + /** + * Add an item at specified index (position). + * Runtime for this is O(n) if it doesn't need to resize with a possible low constant. + * If a resize is triggered the runtime is O(n) with a greater constant. + * + * @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) { + doubleSize(); + if (index < 0 || index > size || size == 0) { + throw new IndexOutOfBoundsException("Index ouf of bounds. NOPE!"); + } else { + for (int i = size; i > index; i--) { + buffer[i] = buffer[i - 1]; + } + buffer[index] = item; + size++; + } + } + + /** + * Get the item at a specified index. + * Runtime for this is O(1). Retrieval is always a constant time function on arrays that are indexed. + * + * @param index the index where the item should be retrieved + * @return the item located at that index + */ + @Override + public E get(int index) { + if (index >= 0 && index < size) { + return buffer[index]; + } else { + throw new IndexOutOfBoundsException("Index cannot be outside the size of the array."); + } + } + + /** + * Set (save) an item at a specified index. Previous + * item at that index is overwritten. + * Runtime for this is O(1). Since it's indexed, there is no search time, so it takes constant time. + * + * @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 (index < 0 || index > size - 1) { + throw new IndexOutOfBoundsException("Index cannot be outside the size of the array."); + } + buffer[index] = item; + } + + /** + * Remove item at the front of the list. + * Runtime for this method is O(n) because of the shifting left that must occur of the remained of the array. + * + * @return the item that was removed + */ + @Override + public E removeFront() { + if (size <= 0) { + throw new NoSuchElementException("Cannot remove element from an empty array"); + } + E result = buffer[0]; + for (int i = 0; i < size; i++) { + buffer[i] = buffer[i + 1]; + } + buffer[size] = null; + size--; + return result; + } + + /** + * Remove item at the back of the list + * Runtime for this method is O(1). It always takes the same time to remove the last element. + * + * @return the item that was removed + */ + @Override + public E removeBack() { + if (size <= 0) { + throw new NoSuchElementException("Cannot remove element from empty array"); + } + E result = buffer[size - 1]; + buffer[size - 1] = null; + size--; + return result; + } + + /** + * Remove item from the list + * Runtime for this is O(n) with a constant of 1. If it's not found it goes through the array once. + * If it is found the second loop picks up where the first loop stopped and finishes looping through. + * Then the first loop finishes looping through the array. It has a constant of ~2. + * + * @param item the item to be removed + */ + @Override + public void remove(E item) { + for (int i = 0; i < size; i++) { + if (buffer[i] == item) { + for (int k = i; k < size - 1; k++) { + buffer[k] = buffer[k + 1]; + } + size--; + } + } + } + + /** + * Remove item at a specified index. + * The runtime of this method is O(n) because the worst case the index provided is 0, and it has to shift + * the whole array left one index. + * + * @param index the index where the item should be removed + * @return the item that was removed + */ + @Override + public E remove(int index) { + E value = null; + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index out of bounds at position " + index); + } else if (index < size - 1) { + value = buffer[index]; + for (int i = index; i < size; i++) { + buffer[i] = buffer[i + 1]; + } + buffer[size] = null; + size--; + } else if (index == size - 1) { + value = buffer[index]; + buffer[index] = null; + size--; + } + return value; + } + + /** + * Checks if an item is in the list. + * This method has a runtime of O(n) because it loops through the array and if the element is not present + * or is the last position, it goes through the whole array. + * + * @param item the item to search for + * @return true if the item is in the list, false otherwise + */ + @Override + public boolean contains(E item) { + for (int i = 0; i < size; i++) { + if (buffer[i] == item) { + return true; + } + } + return false; + } + + /** + * Checks if the list is empty. + * Runtime of this is O(1). It's simply returning a single boolean with no loops. + * + * @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 of this method is O(1). It's returning an int and doesn't loop. + * + * @return number of items in the list + */ + @Override + public int size() { + return size; + } + + /** + * Helper method that doubles the array size using the resize method. + * Runtime for this method is O(1) because it doesn't loop anything and is just a helper method to clean + * up implementation elsewhere of resize. + */ + private void doubleSize() { + if (size == buffer.length) { + resize(buffer.length * 2); + } + } + + /** + * Grows and Shrinks the array as required by data size. + * Runtime for this method is O(n). An arraycopy loops through the original array from start to finish while + * copying. + */ + private void resize(int newSize) { + E[] newBuffer = (E[]) new Object[newSize]; + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + buffer = newBuffer; + } + + + /** + * Custom toString for this arraylist implementation that returns a pretty print display of the contents + * Runtime for this method is O(n).It must loop through the entire array to convert it to a string for printing. + * + * @return a string of the contents of the arraylist + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + if (size > 0) { + for (int i = 0; i < size - 1; i++) { + sb.append(buffer[i]); + sb.append(','); + sb.append(' '); + } + sb.append(buffer[size - 1]); + sb.append(']'); + } else { + return "null"; + } + return sb.toString(); + } + + /** + * Returns an iterator over elements of type {@code T}. + * Runtime for this method is O(1) because it simply8 instantiates an object and returns it. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new ArrayListIterator(); + } + + /** + * Performs the given action for each element of the {@code Iterable} + * until all elements have been processed or the action throws an + * exception. Actions are performed in the order of iteration, if that + * order is specified. Exceptions thrown by the action are relayed to the + * caller. + *

+ * The behavior of this method is unspecified if the action performs + * side effects that modify the underlying source of elements, unless an + * overriding class has specified a concurrent modification policy. + * + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + * @implSpec

The default implementation behaves as if: + *

{@code
+     *     for (T t : this)
+     *         action.accept(t);
+     * }
+ * @since 1.8 + */ + @Override + public void forEach(Consumer action) { + List.super.forEach(action); + } + + /** + * Creates a {@link Spliterator} over the elements described by this + * {@code Iterable}. + * + * @return a {@code Spliterator} over the elements described by this + * {@code Iterable}. + * @implSpec The default implementation creates an + * early-binding + * spliterator from the iterable's {@code Iterator}. The spliterator + * inherits the fail-fast properties of the iterable's iterator. + * @implNote The default implementation should usually be overridden. The + * spliterator returned by the default implementation has poor splitting + * capabilities, is un-sized, and does not report any spliterator + * characteristics. Implementing classes can nearly always provide a + * better implementation. + * @since 1.8 + */ + @Override + public Spliterator spliterator() { + return List.super.spliterator(); + } + + private class ArrayListIterator implements Iterator { + private int i; + + private ArrayListIterator() { + this.i = 0; + } + + /** + * Tracker of if there's a next for the iterator. + * + * @return returns the boolean representing if there's another element after the current element. + */ + public boolean hasNext() { + return i < size; + } + + /** + * Item to retrieve the element values for the iterator. + * Runtime is O(1) because it's only looking at a single location and not looping. + * + * @return the data of the current element. + */ + public E next() { + E currentItem = buffer[i]; + i++; + return currentItem; + } + } +} diff --git a/src/Bag.java b/src/Bag.java new file mode 100644 index 0000000..268662d --- /dev/null +++ b/src/Bag.java @@ -0,0 +1,30 @@ +/** + * Bag is a collection structure + * + * @param class / data type of the items in the bag + * @author Rob Smith + * @version 1.0 + */ +public interface Bag extends Iterable { + + /** + * Add an item to the bag. + * + * @param item the item to be added + */ + void add(E item); + + /** + * Checks to see if the bag is empty. + * + * @return true if the bag is empty, false otherwise + */ + boolean isEmpty(); + + /** + * Returns a count of the number of items in the bag. + * + * @return the number of items in the bag + */ + int size(); +} diff --git a/src/Deque.java b/src/Deque.java index 0107f47..c0772a5 100644 --- a/src/Deque.java +++ b/src/Deque.java @@ -7,36 +7,42 @@ public interface Deque extends Iterable { /** * Checks if the deque is empty. + * * @return true if the deque is empty, false otherwise */ boolean isEmpty(); /** * Returns the number of items in the deque. + * * @return number of items in the deque */ int size(); /** * Add an item to the left end of the deque. + * * @param item item to be added */ void pushLeft(E item); /** * Add an item to the right end of the deque. + * * @param item */ void pushRight(E item); /** * Remove an item from the left end of the deque. + * * @return */ E popLeft(); /** * Remove an item from the right end of the deque. + * * @return */ E popRight(); diff --git a/src/LinkedBag.java b/src/LinkedBag.java new file mode 100644 index 0000000..1870165 --- /dev/null +++ b/src/LinkedBag.java @@ -0,0 +1,107 @@ +import java.util.Iterator; + +/** + * * Implementation of the LinkedBag using the Bag interface. This is my term assignment 2 Bag. + * + * @param class / data type of the items in the LinkedBag + * @author Rob Smith + * @version 1.0 + */ +public class LinkedBag implements Bag { + private Node head; + private int size; + + private class Node { + E data; + Node next; + } + + /** + * Constructor for the linkedBay class. + */ + public LinkedBag() { + this.head = null; + this.size = 0; + } + + /** + * Adds the specified object to the front of the bag. + * Runtime of this is O(1). It always takes the same amount of time to add a node to the front of a linked list + * because there is no looping to shift like in an array. + * + * @param item the item to be added + */ + public void add(E item) { + Node newNode = new Node(); + newNode.data = item; + if (head != null) { + newNode.next = head; + } + head = newNode; + this.size++; + } + + /** + * Checks if the bag is empty. + * Runtime of this is O(1). It's simply returning a single boolean with no loops. + * + * @return true if the LinkedBag is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Checks the size of the bag. + * Runtime of this is O(1). It's simply returning a single int with no loops. + * + * @return the size of the LinkedBag + */ + @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(); + } + + private class LinkedBagIterator implements Iterator { + Node 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.) + * Runtime is O(1) because there is no looping involved it is just checking where in the bag the + * iterator is currently located. + * + * @return {@code true} if the iteration has more elements + */ + @Override + public boolean hasNext() { + return current != null; + } + + /** + * Returns the next element in the iteration. + * Runtime for this is O(1) because it's only accessing a single point of data not looping through the + * bag in its entirety. + * + * @return the next element in the iteration + */ + @Override + public E next() { + E value = current.data; + current = current.next; + return value; + } + } +} diff --git a/src/LinkedList.java b/src/LinkedList.java new file mode 100644 index 0000000..15f9a15 --- /dev/null +++ b/src/LinkedList.java @@ -0,0 +1,443 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Spliterator; +import java.util.function.Consumer; + +/** + * Implementation of the LinkedList using the List interface. This is my term assignment 1 Linked List. + * + * @param class / data type of the items in the LinkedList + * @author Rob Smith + * @version 1.0 + */ +public class LinkedList implements List { + private class Node { + E data; + Node next; + } + + private Node head; + private int size; + + /** + * Constructor for the LinkedList class. + * Runtime is O(1) as it always takes the same time to construct. + */ + public LinkedList() { + head = null; + size = 0; + } + + /** + * Add item to the front. + * Runtime of adding to front for a linked-list is always O(1). Adding to the front takes the same amount + * of time regardless of the size of the list or it's contents. + * + * @param item the item to be added + */ + @Override + public void addFront(E item) { + Node newNode = new Node(); + newNode.data = item; + if (head != null) { + newNode.next = head; + } + head = newNode; + this.size++; + } + + /** + * Add item to the back. + * Runtime of this method is O(n) because a linked list must walk through the list to locate the back of the list + * before it can add a node to the back location. + * + * @param item the item to be added + */ + @Override + public void addBack(E item) { + Node current = head; + Node newNode = new Node(); + newNode.data = item; + + if (current == null) { + addFront(item); + } else { + while (current.next != null) { + current = current.next; + } + current.next = newNode; + size++; + } + } + + /** + * Add an item at specified index (position). + * Runtime for this method is O(n) because the worst case is that it must add a node to the end, the back. Adding + * tot the back is a single traversal of the complete list, yielding O(n). + * + * @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 (index < 0 || index > size) { + throw new IndexOutOfBoundsException("Index out of bounds"); + } + Node newNode = new Node(); + newNode.data = item; + if (index == 0) { + this.addFront(item); + } else if (index == size) { + this.addBack(item); + } else { + Node current = head.next; + Node previous = head; + int currentIndex = 1; + while (current != null) { + if (currentIndex == index) { + newNode.next = current; + previous.next = newNode; + size++; + } + previous = current; + current = current.next; + currentIndex++; + } + } + } + + /** + * Get the item at a specified index. + * Runtime for this method is O(n) because if the index is the last element of the list it must traverse the + * entire list to retrieve the data from the last 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 (head == null) { + throw new NoSuchElementException("The list is empty"); + } else if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index out of bounds"); + } + int currentIndex = 0; + Node current = head; + while (current != null) { + if (currentIndex == index) { + return current.data; + } + current = current.next; + currentIndex++; + } + return null; + } + + /** + * Set (save) an item at a specified index. Previous + * item at that index is overwritten. + * Run time for this method is O(n) because the index can be the last position of the linked list, so it can run + * through one entire traversal of the linked list. + * + * @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 (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index out of bounds"); + } else if (head == null && index > 0) { + throw new NoSuchElementException("Empty List"); + } else if (index == 0) { + assert head != null; + head.data = item; + } + Node current = head.next; + + int currentIndex = 1; + while (current != null) { + if (currentIndex == index) { + current.data = item; + } + current = current.next; + currentIndex++; + } + } + + /** + * Remove item at the front of the list. + * This is always a runtime of O(1). It takes the same time to remove the first node regardless of the size of + * the linked list. + * + * @return the item that was removed + */ + @Override + public E removeFront() { + if (head == null) { + throw new NoSuchElementException("The list is empty"); + } else { + E result = head.data; + head = head.next; + size--; + return result; + } + } + + /** + * Remove item at the back of the list + * Runtime for this is always O(n) because a singly linked list must be traversed in its entirety to remove + * the last node of the linked list. + * + * @return the item that was removed + */ + @Override + public E removeBack() { + Node current = head; + if (head == null) { + throw new NoSuchElementException("The list is empty"); + } else if (current.next == null) { + E result = current.data; + head = null; + size--; + return result; + } + while (current.next.next != null) { + current = current.next; + } + E result = current.data; + current.next = null; + size--; + return result; + } + + /** + * Remove item from the list + * This method has run a time of O(n) because it must traverse the linked list to find the item in the parameter. + * It may not find the item, so it will go through the entire linked list. + * + * @param item the item to be removed + */ + @Override + public void remove(E item) { + if (head == null) { + return; + } + Node current = head; + Node previous = current.next; + while (current != null) { + if (current.data == item) { + current.data = (E) (Integer) 0; + previous.next = current.next; + size--; + } + previous = current; + current = current.next; + } + } + + /** + * Remove item at a specified index. + * Runtime for remove() is O(n) because it must loop through the linked list until it reaches the specified + * index, and then remove the item from the list. This could be the last node, so its O(n). + * + * @param index the index where the item should be removed + * @return the item that was removed + */ + @Override + public E remove(int index) { + E value = null; + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index out of bounds"); + } else if (head == null) { + throw new NoSuchElementException("Empty List"); + } else if (index == 0) { + value = head.data; + head.data = (E) (Integer) 0; + head = head.next; + size--; + return value; + } + + Node current = head.next; + Node previous = head; + int currentIndex = 1; + while (current != null) { + if (currentIndex == index) { + value = current.data; + current.data = (E) (Integer) 0; + previous.next = current.next; + size--; + break; + } + previous = current; + current = current.next; + currentIndex++; + } + return value; + } + + /** + * Checks if an item is in the list. + * Runtime for this method is O(n) because the method must loop through the linked list to find the item + * and check if it matches the node data item. + * + * @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 (head == null) { + return false; + } + Node current = head; + while (current.next != null) { + if (current.data == item) { + return true; + } + current = current.next; + } + return false; + } + + /** + * Checks if the list is empty. + * Runtime for this method is O(1) since we're just checking a variable and returning a boolean on a single + * condition without looping. + * + * @return true if the list is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return this.size == 0; + } + + /** + * Provides a count of the number of items in the list. + * Runtime for this method is O(1) since we're just checking a variable and returning its value. + * + * @return number of items in the list + */ + @Override + public int size() { + return this.size; + } + + /** + * Pretty printing method for printing a LinkedList. + * Runtime for toString is always O(n) because it is walking through the linked list to the end. + * + * @return String of the node data in the linked list. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + + if (size > 0) { + Node current = head; + do { + sb.append(current.data); + if (current.next != null) { + sb.append(','); + sb.append(' '); + } + current = current.next; + } while (current != null); + sb.append(']'); + } else { + return "null"; + } + + return sb.toString(); + } + + /** + * Returns an iterator over elements of type {@code T}. + * Runtime is I(1) because it only instantiates an object and returns it there is no looping. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new LinkedListIterator(); + } + + /** + * Performs the given action for each element of the {@code Iterable} + * until all elements have been processed or the action throws an + * exception. Actions are performed in the order of iteration, if that + * order is specified. Exceptions thrown by the action are relayed to the + * caller. + *

+ * The behavior of this method is unspecified if the action performs + * side effects that modify the underlying source of elements, unless an + * overriding class has specified a concurrent modification policy. + * + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + * @implSpec

The default implementation behaves as if: + *

{@code
+     *     for (T t : this)
+     *         action.accept(t);
+     * }
+ * @since 1.8 + */ + @Override + public void forEach(Consumer action) { + List.super.forEach(action); + } + + /** + * Creates a {@link Spliterator} over the elements described by this + * {@code Iterable}. + * + * @return a {@code Spliterator} over the elements described by this + * {@code Iterable}. + * @implSpec The default implementation creates an + * early-binding + * spliterator from the iterable's {@code Iterator}. The spliterator + * inherits the fail-fast properties of the iterable's iterator. + * @implNote The default implementation should usually be overridden. The + * spliterator returned by the default implementation has poor splitting + * capabilities, is un-sized, and does not report any spliterator + * characteristics. Implementing classes can nearly always provide a + * better implementation. + * @since 1.8 + */ + @Override + public Spliterator spliterator() { + return List.super.spliterator(); + } + + private class LinkedListIterator implements Iterator { + private int i; + Node current = head; + + private LinkedListIterator() { + this.i = 0; + } + + /** + * Tracker of if there's a next for the iterator. + * + * @return returns the boolean representing if there's another element after the current element. + */ + public boolean hasNext() { + return i < size; + } + + /** + * Item to retrieve the element values for the iterator. + * Runtime is O(1) because it's only looking at a single location and not looping. + * + * @return the data of the current element. + */ + public E next() { + E currentItem = current.data; + current = current.next; + i++; + return currentItem; + } + } + +} diff --git a/src/LinkedQueue.java b/src/LinkedQueue.java new file mode 100644 index 0000000..698f2a9 --- /dev/null +++ b/src/LinkedQueue.java @@ -0,0 +1,134 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * * Implementation of the LinkedQueue using the Queue interface. This is my term assignment 2 FIFO Queue. + * + * @param class / data type of the items in the LinkedQueue + * @author Rob Smith + * @version 1.0 + */ +public class LinkedQueue implements Queue { + private Node oldest; + private Node newest; + private int size; + + /** + * Constructor for LinkedQueue class. + */ + public LinkedQueue() { + this.oldest = null; + this.newest = null; + this.size = 0; + } + + private class Node { + E data; + Node next; + } + + /** + * Checks if the queue is empty. + * Runtime of this is O(1). It's simply returning a single boolean with no loops. + * + * @return true if the LinkedQueue is empty, false otherwise + */ + public boolean isEmpty() { + return size == 0; + } + + /** + * Checks the size of the list. + * Runtime of this is O(1). It's simply returning a single int with no loops. + * + * @return the size of the LinkedQueue + */ + public int size() { + return size; + } + + /** + * Adds the specified object to the front of the list. + * Runtime of this is O(1). It always takes the same amount of time to add a node to the end of a linked list when + * using a second pointer because we don't need to traverse the linked list to locate the end node. + * + * @param item the item to be added + */ + public void enqueue(E item) { + Node newNode = new Node(); + if (size == 0) { + newest = newNode; + oldest = newest; + } else { + newest.next = newNode; + newest = newNode; + } + newNode.data = item; + newest.next = null; + size++; + + } + + /** + * Dequeue removes the last element in the linked list and returns the value of the data inside it. + * Runtime for this operation is O(1), removing the last element is a constant time operation regardless of the + * size of the list since we're tracking it with a tail pointer. + * + * @return the data from the node removed from the list. + */ + public E dequeue() { + if (oldest == null) { + throw new NoSuchElementException("The list is empty"); + } else { + E result = oldest.data; + oldest = oldest.next; + size--; + if (isEmpty()) { + newest = null; + } + return result; + } + } + + /** + * returns an object to iterate through the LinkedQueue. + * Runtime is O(1) because it is merely instantiating an object with no looping. + * + * @return an object to iterate through the LinkedQueue + */ + @Override + public Iterator iterator() { + return new LinkedQueueIterator(); + } + + private class LinkedQueueIterator implements Iterator { + + private Node current = oldest; + + /** + * 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.) + * Runtime is O(1) because there is no looping involved it is just checking where int he LinkedQueue the + * iterator is currently located. + * + * @return {@code true} if the current position is not the end of the list, aka, null. + */ + public boolean hasNext() { + return current != null; + } + + /** + * Returns the next element in the iteration. + * Runtime for this is O(1) because it's only accessing a single point of data not looping through the + * LinkedQueue in its entirety. + * + * @return the next element in the iteration + */ + public E next() { + E value = current.data; + current = current.next; + return value; + } + } +} diff --git a/src/LinkedStack.java b/src/LinkedStack.java new file mode 100644 index 0000000..ee0c2df --- /dev/null +++ b/src/LinkedStack.java @@ -0,0 +1,140 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Linked Node stack implementation. LIFO. + * + * @param class / data type of the items in the LinkedStack + * @author Rob smith + * @version 1.0 + */ +public class LinkedStack implements Stack { + + private Node head; + private int size; + + private class Node { + E data; + Node next; + } + + /** + * Constructor for LinkedStack class. + */ + public LinkedStack() { + this.head = null; + this.size = 0; + } + + /** + * Checks if the list is empty. + * Runtime of this is O(1). It's simply returning a single boolean with no loops. + * + * @return true if the LinkedStack is empty, false otherwise + */ + public boolean isEmpty() { + return size == 0; + } + + /** + * Checks the size of the list. + * Runtime of this is O(1). It's simply returning a single int with no loops. + * + * @return the size of the LinkedStack + */ + public int size() { + return size; + } + + /** + * Adds the specified object to the front of the list. + * Runtime of this is O(1). It always takes the same amount of time to add a node to the front of a linked list + * because there is no looping to shift like in an array. + * + * @param item the item to be added + */ + public void push(E item) { + Node newNode = new Node(); + newNode.data = item; + if (head != null) { + newNode.next = head; + } + head = newNode; + this.size++; + } + + + /** + * Pop removes the first element in the linked list and returns the value of the data inside it. + * Runtime for this operation is O(1), removing the first element is a constant time operation regardless of the + * size of the list. + * + * @return the data from the node removed from the list. + */ + public E pop() { + if (head == null) { + throw new NoSuchElementException("The list is empty"); + } else { + E result = head.data; + head = head.next; + size--; + return result; + } + } + + /** + * Returns the item at the top of the stack. + * Does not modify the stack or the item at the top. + * Runtime is O(1) because there is no looping involved.) + * + * @return item at the top of the stack. + */ + @Override + public E peek() { + return head.data; + } + + /** + * returns an object to iterate through the Linked-stack. + * Runtime is O(1) because it is merely instantiating an object with no looping. + * + * @return an object to iterate through the Linked-stack + */ + public Iterator iterator() { + return new LinkedStackIterator(); + } + + private class LinkedStackIterator implements Iterator { + + Node 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.) + * Runtime is O(1) because there is no looping involved it is just checking where int he LinkedStack the + * iterator is currently located. + * + * @return {@code true} if the current position is not the end of the list, aka, null. + */ + @Override + public boolean hasNext() { + return current != null; + } + + /** + * Returns the next element in the iteration. + * Runtime for this is O(1) because it's only accessing a single point of data not looping through the + * LinkedStack in its entirety. + * + * @return the next element in the iteration + */ + @Override + public E next() { + E value = current.data; + current = current.next; + return value; + } + } + +} diff --git a/src/LinkedStackTestClient.java b/src/LinkedStackTestClient.java new file mode 100644 index 0000000..8cf5428 --- /dev/null +++ b/src/LinkedStackTestClient.java @@ -0,0 +1,26 @@ +import java.util.Scanner; + +/** + * LinkedStackTestClient for term-project assignment 2 to implement and test a Stack ADT class, LinkedStack. + * + * @author Rob Smith + * @version 1.0 + */ +public class LinkedStackTestClient { + + public static void main(String[] args) { + + Stack stringStack = new LinkedStack<>(); + Scanner in = new Scanner("to be or not to - be - - that - - - is"); + + while (in.hasNext()) { + String item = in.next(); + if (!item.equals("-")) { + stringStack.push(item); + } else if (!stringStack.isEmpty()) { + System.out.print(stringStack.pop() + " "); + } + } + System.out.println("(" + stringStack.size() + " left on the stack" + ")"); + } +} diff --git a/src/Main.java b/src/Main.java index 8f8f984..49a1c3f 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,3 +1,9 @@ +/** + * Implementation of the LinkedList and ArrayList using the List interface. This is my term assignment 1. + * + * @author Rob Smith + * " + */ //TIP To Run code, press or // click the icon in the gutter. public class Main { @@ -5,6 +11,6 @@ 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!"); - + System.out.println("This was a good project, I learned a lot."); } -} \ No newline at end of file +} diff --git a/src/QueueTestClient.java b/src/QueueTestClient.java new file mode 100644 index 0000000..6483531 --- /dev/null +++ b/src/QueueTestClient.java @@ -0,0 +1,26 @@ +import java.util.Scanner; + +/** + * Queue test client for term-project assignment 2 to implement and test a Stack ADT class, LinkedQueue. + * + * @author Rob Smith + * @version 1.0 + */ +public class QueueTestClient { + + public static void main(String[] args) { + + Queue stringQueue = new LinkedQueue<>(); + Scanner in = new Scanner("to be or not to - be - - that - - - is"); + + while (in.hasNext()) { + String item = in.next(); + if (!item.equals("-")) { + stringQueue.enqueue(item); + } else if (!stringQueue.isEmpty()) { + System.out.print(stringQueue.dequeue() + " "); + } + } + System.out.println("(" + stringQueue.size() + " left on the stack" + ")"); + } +} diff --git a/src/ResizingArrayStack.java b/src/ResizingArrayStack.java new file mode 100644 index 0000000..4004e01 --- /dev/null +++ b/src/ResizingArrayStack.java @@ -0,0 +1,127 @@ +import java.util.Iterator; + +/** + * Stack (LIFO: last-in, first-out) API for resizing array implementation + * + * @param class / data type of the items in the Stack + * @author Rob Smith + * @version 1.0 + */ +public class ResizingArrayStack implements Stack { + private E[] buffer; + private int size; + + /** + * Constructor for the ResizingArrayStack class. + */ + public ResizingArrayStack() { + this.size = 0; + buffer = (E[]) new Object[10]; + } + + private void resize(int max) { + E[] temp = (E[]) new Object[max]; + if (size >= 0) { + System.arraycopy(buffer, 0, temp, 0, size); + } + buffer = temp; + } + + /** + * Add an item to the stack. + * This method is a O(1) operation if a resize is not triggered because it doesn't loop through the array. + * If resize is triggered it becomes O(n) because resize loops through the entire array to size it up. + * + * @param item the item to be added + */ + @Override + public void push(E item) { + if (size == buffer.length) { + resize(2 * buffer.length); + } + buffer[size] = item; + size++; + } + + /** + * Removes the most recently added item from the stack. + * Runtime for this method is O(1) if a resize is not triggered because it doesn't loop through the array. + * If resize is triggered it becomes O(n) because resize loops through the entire array. + * + * @return the item that was removed + */ + @Override + public E pop() { + E value = buffer[size - 1]; + buffer[size - 1] = null; + if (size == buffer.length / 4) { + resize(buffer.length / 2); + } + size--; + return value; + } + + /** + * Returns the item at the top of the stack. + * Does not modify the stack or the item at the top. + * The runtime for this method is O(1) because there is no looping, it simply retrieves an item. + * + * @return item at the top of the stack. + */ + @Override + public E peek() { + return buffer[size - 1]; + } + + /** + * Checks to see if the stack is empty. + * Runtime of O(1), single check of variable with no looping. + * + * @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 of O(1), single check of variable with no looping. + * + * @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 ReverseArrayIterator(); + } + + private class ReverseArrayIterator implements Iterator { + private int iterSize = size; + + public boolean hasNext() { + return iterSize > 0; + } + + public E next() { + E value = buffer[iterSize - 1]; + iterSize--; + return value; + } + + /** + * Unused method in this implementation. + */ + public void remove() { + } + } +} diff --git a/src/StackTestClient.java b/src/StackTestClient.java new file mode 100644 index 0000000..421baae --- /dev/null +++ b/src/StackTestClient.java @@ -0,0 +1,25 @@ +import java.util.Scanner; + +/** + * StackTestClient for term-project assignment 2 to implement and test a Stack ADT class, ResizingArrayStack. + * + * @author Rob Smith + * @version 1.0 + */ +public class StackTestClient { + public static void main(String[] args) { + + Stack stringStack = new ResizingArrayStack<>(); + Scanner in = new Scanner("to be or not to - be - - that - - - is"); + + while (in.hasNext()) { + String item = in.next(); + if (!item.equals("-")) { + stringStack.push(item); + } else if (!stringStack.isEmpty()) { + System.out.print(stringStack.pop() + " "); + } + } + System.out.println("(" + stringStack.size() + " left on the stack" + ")"); + } +} diff --git a/src/Stats.java b/src/Stats.java new file mode 100644 index 0000000..d79cfb8 --- /dev/null +++ b/src/Stats.java @@ -0,0 +1,33 @@ +import java.util.Scanner; + +/** + * LinkedBag test client for term-project assignment 2 to implement and test a Stack ADT class, LinkedBag. + * + * @author Rob Smith + * @version 1.0 + */ +public class Stats { + public static void main(String[] args) { + + Bag numbers = new LinkedBag<>(); + Scanner in = new Scanner("100 99 101 120 98 107 109 81 101 90"); + while (in.hasNextDouble()) { + numbers.add(in.nextDouble()); + } + double sum = 0.0; + for (double x : numbers) { + sum += x; + } + double mean = sum / numbers.size(); + + sum = 0.0; + for (double x : numbers) { + sum += (x - mean) * (x - mean); + } + double std = Math.sqrt(sum / (numbers.size() - 1)); + + System.out.printf("Mean: %.2f\n", mean); + System.out.printf("Std dev: %.2f\n", std); + } + +}