diff --git a/Tests/ArrayListTests.java b/Tests/ArrayListTests.java new file mode 100644 index 0000000..39d7aa9 --- /dev/null +++ b/Tests/ArrayListTests.java @@ -0,0 +1,309 @@ +import static org.junit.Assert.*; +import org.junit.Test; + +import java.util.Iterator; + +public class ArrayListTests { + @Test + public void testAddFrontEmptyList() { + ArrayList list = new ArrayList<>(); + list.addFront(5); + assertEquals(1, list.size()); + assertEquals(Integer.valueOf(5), list.get(0)); + } + + @Test + public void testAddFrontNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addFront(5); + list.addFront(10); + assertEquals(2, list.size()); + assertEquals(Integer.valueOf(10), list.get(0)); + assertEquals(Integer.valueOf(5), list.get(1)); + } + + @Test + public void testAddFrontNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + list.addFront(100); + assertEquals(11, list.size()); + assertEquals(Integer.valueOf(100), list.get(0)); + } + + @Test + public void testAddBackEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + assertEquals(1, list.size()); + assertEquals(Integer.valueOf(5), list.get(0)); + } + + @Test + public void testAddBackNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + list.addBack(10); + assertEquals(2, list.size()); + assertEquals(Integer.valueOf(5), list.get(0)); + assertEquals(Integer.valueOf(10), list.get(1)); + } + + @Test + public void testAddBackNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + list.addBack(100); + assertEquals(11, list.size()); + assertEquals(Integer.valueOf(0), list.get(0)); + assertEquals(Integer.valueOf(100), list.get(10)); + } + + @Test + public void testAddEmptyList() { + ArrayList list = new ArrayList<>(); + list.add(0, 5); + assertEquals(1, list.size()); + assertEquals(Integer.valueOf(5), list.get(0)); + } + + @Test + public void testAddNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.add(0, 5); + list.add(1, 10); + assertEquals(2, list.size()); + assertEquals(Integer.valueOf(5), list.get(0)); + assertEquals(Integer.valueOf(10), list.get(1)); + } + + @Test + public void testAddNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + list.add(5, 100); + assertEquals(11, list.size()); + assertEquals(Integer.valueOf(100), list.get(5)); + assertEquals(Integer.valueOf(5), list.get(6)); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testAddIndexOutOfBounds() { + ArrayList list = new ArrayList<>(); + list.add(1, 5); + } + + @Test + public void testGetNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + assertEquals(Integer.valueOf(5), list.get(0)); + } + + @Test + public void testGetNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + assertEquals(Integer.valueOf(5), list.get(5)); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testGetIndexOutOfBounds() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + list.get(1); + } + + @Test + public void testSetNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + list.set(0, 10); + assertEquals(Integer.valueOf(10), list.get(0)); + } + + @Test + public void testSetNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + list.set(5, 100); + assertEquals(Integer.valueOf(100), list.get(5)); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testSetIndexOutOfBounds() { + ArrayList list = new ArrayList<>(); + list.set(1, 5); + } + + @Test + public void testRemoveFrontNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + assertEquals(Integer.valueOf(5), list.removeFront()); + assertTrue(list.isEmpty()); + } + + @Test + public void testRemoveFrontNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + assertEquals(Integer.valueOf(0), list.removeFront()); + assertEquals(9, list.size()); + assertEquals(Integer.valueOf(1), list.get(0)); + } + + @Test + public void testRemoveBackNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + assertEquals(Integer.valueOf(5), list.removeBack()); + assertTrue(list.isEmpty()); + } + + @Test + public void testRemoveBackNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + assertEquals(Integer.valueOf(9), list.removeBack()); + assertEquals(9, list.size()); + } + + @Test + public void testRemoveEmptyList() { + ArrayList list = new ArrayList<>(); + list.remove(Integer.valueOf(5)); + assertTrue(list.isEmpty()); + } + + @Test + public void testRemoveNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + list.remove(Integer.valueOf(5)); + assertTrue(list.isEmpty()); + } + + @Test + public void testRemoveNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + list.remove(Integer.valueOf(5)); + assertEquals(9, list.size()); + assertFalse(list.contains(5)); + } + + @Test + public void testRemoveIndexNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + assertEquals(Integer.valueOf(5), list.remove(0)); + assertTrue(list.isEmpty()); + } + + @Test + public void testRemoveIndexNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + assertEquals(Integer.valueOf(5), list.remove(5)); + assertEquals(9, list.size()); + assertFalse(list.contains(5)); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testRemoveIndexOutOfBounds() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + list.remove(1); + } + + @Test + public void testContainsEmptyList() { + ArrayList list = new ArrayList<>(); + assertFalse(list.contains(5)); + } + + @Test + public void testContainsNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + assertTrue(list.contains(5)); + } + + @Test + public void testContainsNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + assertTrue(list.contains(5)); + } + + @Test + public void testIsEmptyEmptyList() { + ArrayList list = new ArrayList<>(); + assertTrue(list.isEmpty()); + } + + @Test + public void testIsEmptyNonEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + assertFalse(list.isEmpty()); + } + + @Test + public void testSizeEmptyList() { + ArrayList list = new ArrayList<>(); + assertEquals(0, list.size()); + } + + @Test + public void testSizeNearlyEmptyList() { + ArrayList list = new ArrayList<>(); + list.addBack(5); + assertEquals(1, list.size()); + } + + @Test + public void testSizeNonEmptyList() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + assertEquals(10, list.size()); + } + + @Test + public void testIterator() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.addBack(i); + } + + Iterator iterator = list.iterator(); + int count = 0; + while (iterator.hasNext()) { + assertEquals(Integer.valueOf(count), iterator.next()); + count++; + } + } +} diff --git a/Tests/LinkedListTests.java b/Tests/LinkedListTests.java new file mode 100644 index 0000000..183110d --- /dev/null +++ b/Tests/LinkedListTests.java @@ -0,0 +1,159 @@ +import static org.junit.Assert.*; +import org.junit.Test; + +public class LinkedListTests { + @Test + public void testAddFrontEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + assertEquals(Integer.valueOf(5), list.get(0)); + assertEquals(1, list.size()); + } + + @Test + public void testAddFrontNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + list.addFront(10); + assertEquals(Integer.valueOf(10), list.get(0)); + assertEquals(Integer.valueOf(5), list.get(1)); + assertEquals(2, list.size()); + } + + @Test + public void testAddBackEmptyList() { + LinkedList list = new LinkedList<>(); + list.addBack(5); + assertEquals(Integer.valueOf(5), list.get(0)); + assertEquals(1, list.size()); + } + + @Test + public void testAddBackNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addBack(5); + list.addBack(10); + assertEquals(Integer.valueOf(5), list.get(0)); + assertEquals(Integer.valueOf(10), list.get(1)); + assertEquals(2, list.size()); + } + + @Test + public void testGetEmptyList() { + LinkedList list = new LinkedList<>(); + assertNull(list.get(0)); + } + + @Test + public void testGetNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + list.addFront(10); + assertEquals(Integer.valueOf(10), list.get(0)); + assertEquals(Integer.valueOf(5), list.get(1)); + } + + @Test + public void testSetEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + list.set(0, 10); + assertEquals(Integer.valueOf(10), list.get(0)); + } + + @Test + public void testSetNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + list.addFront(10); + list.set(1, 20); + assertEquals(Integer.valueOf(10), list.get(0)); + assertEquals(Integer.valueOf(20), list.get(1)); + } + + @Test + public void testRemoveFrontEmptyList() { + LinkedList list = new LinkedList<>(); + assertNull(list.removeFront()); + } + + @Test + public void testRemoveFrontNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + list.addFront(10); + assertEquals(Integer.valueOf(10), list.removeFront()); + assertEquals(1, list.size()); + } + + @Test + public void testRemoveBackEmptyList() { + LinkedList list = new LinkedList<>(); + assertNull(list.removeBack()); + } + + @Test + public void testRemoveBackNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + list.addFront(10); + assertEquals(Integer.valueOf(5), list.removeBack()); + assertEquals(1, list.size()); + } + + @Test + public void testRemoveEmptyList() { + LinkedList list = new LinkedList<>(); + assertNull(list.remove(0)); + } + + @Test + public void testRemoveNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + list.addFront(10); + assertEquals(Integer.valueOf(5), list.remove(1)); + assertEquals(1, list.size()); + } + + @Test + public void testContainsEmptyList() { + LinkedList list = new LinkedList<>(); + assertFalse(list.contains(5)); + } + + @Test + public void testContainsNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + list.addFront(10); + assertTrue(list.contains(5)); + } + + @Test + public void testIsEmptyEmptyList() { + LinkedList list = new LinkedList<>(); + assertTrue(list.isEmpty()); + } + + @Test + public void testIsEmptyNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + assertFalse(list.isEmpty()); + } + + @Test + public void testSizeEmptyList() { + LinkedList list = new LinkedList<>(); + assertEquals(0, list.size()); + } + + @Test + public void testSizeNonEmptyList() { + LinkedList list = new LinkedList<>(); + list.addFront(5); + list.addFront(10); + assertEquals(2, list.size()); + } +} diff --git a/Tests/QueueTestClient.java b/Tests/QueueTestClient.java new file mode 100644 index 0000000..9cd0f96 --- /dev/null +++ b/Tests/QueueTestClient.java @@ -0,0 +1,17 @@ +import java.util.Scanner; + +public class QueueTestClient { + public static void main(String[] args) { + Queue queue = new LinkedQueue(); + Scanner console = new Scanner("to be or not to - be - - that - - - is"); + while (console.hasNext()) { + String item = console.next(); + if (!item.equals("-")) { + queue.enqueue(item); + } else if (!queue.isEmpty()) { + System.out.print(queue.dequeue() + " "); + } + } + System.out.println("(" + queue.size() + " left in the queue)"); + } +} \ No newline at end of file diff --git a/Tests/StackTestClient.java b/Tests/StackTestClient.java new file mode 100644 index 0000000..e74382c --- /dev/null +++ b/Tests/StackTestClient.java @@ -0,0 +1,36 @@ +import java.util.Scanner; + +public class StackTestClient { + public static void main(String[] args) { + Stack stack = new ResizingArrayStack(); + Scanner console = new Scanner("to be or not to - be - - that - - - is"); + while (console.hasNext()) { + String item = console.next(); + if (item.equals("-")) { + if (!stack.isEmpty()) { + System.out.println(stack.pop() + " "); + } + } else { + stack.push(item); + } + } + System.out.println("(" + stack.size() + " left on the stack)"); + + System.out.println(); + System.out.println(); + + Stack s = new LinkedStack(); + Scanner in = new Scanner("to be or not to - be - - that - - - is"); + while (in.hasNext()) { + String item = in.next(); + if (item.equals("-")) { + if (!s.isEmpty()) { + System.out.println(s.pop() + " "); + } + } else { + s.push(item); + } + } + System.out.println("(" + s.size() + " left on the stack)"); + } +} diff --git a/Tests/Stats.java b/Tests/Stats.java new file mode 100644 index 0000000..6f5ee10 --- /dev/null +++ b/Tests/Stats.java @@ -0,0 +1,35 @@ +import java.util.Scanner; + +public class Stats { + public static void main(String[] args) { + Bag numbers = new LinkedBag<>(); + Scanner console = new Scanner("100 99 101 120 98 107 109 81 101 90"); + while (console.hasNextDouble()) { + numbers.add(console.nextDouble()); + } + console.close(); + + int count = 0; + double sum = 0; + double sumOfSquares = 0; + + for (double num : numbers) { + count++; + sum += num; + sumOfSquares += num * num; + } + + double mean = sum / count; + double variance = (sumOfSquares / count) - (mean * mean); + double stddev = Math.sqrt(variance); + + // Print numbers + for (double num : numbers) { + System.out.println(num); + } + + // Print mean and standard deviation + System.out.printf("%nMean: %.2f%n", mean); + System.out.printf("Stddev: %.2f%n", stddev); + } +} \ No newline at end of file diff --git a/src/ArrayList.java b/src/ArrayList.java new file mode 100644 index 0000000..e220940 --- /dev/null +++ b/src/ArrayList.java @@ -0,0 +1,286 @@ +import java.util.Iterator; +import java.util.*; + +/** + * Implementation of a dynamic array-based list. + * + * @author Noah Lanctot + * @version 1.0 + * @param the type of elements in this list + */ +public class ArrayList implements List { + private int size; + private E[] buffer; + + /** + * Constructs an empty ArrayList with an initial capacity of 10. + */ + public ArrayList() { + size = 0; + buffer = (E[]) new Object[10]; + } + + /** + * Adds the specified element to the front of this list. + * If the internal buffer is full, this method resizes the buffer. + * This method has a worst-case runtime complexity of O(n), + * where n is the number of elements in the list, because it may + * need to shift all existing elements to the right. + * + * @param item the element to be added to the front of this list + */ + @Override + public void addFront(E item) { + if (size == buffer.length) { + resize(); + } + for (int i = size; i >= 1; i--) { + buffer[i] = buffer[i - 1]; + } + buffer[0] = item; + size++; + } + + /** + * Adds the specified element to the back of this list. + * If the internal buffer is full, this method resizes the buffer. + * This method has a worst-case runtime complexity of O(1), + * as it simply inserts the element at the end of the buffer. + * + * @param item the element to be added to the back of this list + */ + @Override + public void addBack(E item) { + if (size == buffer.length) { + resize(); + } + buffer[size++] = item; + } + + /** + * Adds the specified element at the specified index in this list. + * If the internal buffer is full, this method resizes the buffer. + * This method has a worst-case runtime complexity of O(n), + * where n is the number of elements in the list, because it may + * need to shift all existing elements after the specified index to the right. + * + * @param index the index at which the specified element is to be inserted + * @param item the element to be inserted + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public void add(int index, E item) { + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException("Index is out of bounds"); + } + if (size == buffer.length) { + resize(); + } + for (int i = size; i > index; i--) { + buffer[i] = buffer[i - 1]; + } + buffer[index] = item; + size++; + } + + /** + * Returns the element at the specified index in this list. + * This method has a worst-case runtime complexity of O(1), + * as it accesses the element directly by index. + * + * @param index the index of the element to return + * @return the element at the specified index in this list + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public E get(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index is out of bounds"); + } + return buffer[index]; + } + + /** + * Replaces the element at the specified index in this list with the specified element. + * This method has a worst-case runtime complexity of O(1), + * as it accesses the element directly by index. + * + * @param index the index of the element to replace + * @param item the element to be stored at the specified index + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public void set(int index, E item) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index is out of bounds"); + } + buffer[index] = item; + } + + /** + * Removes and returns the element at the front of this list. + * This method has a worst-case runtime complexity of O(n), + * where n is the number of elements in the list, because it may + * need to shift all existing elements to the left. + * + * @return the element at the front of this list + * @throws NoSuchElementException if this list is empty + */ + @Override + public E removeFront() { + if (isEmpty()) { + throw new NoSuchElementException("List is empty"); + } + E removedItem = buffer[0]; + for (int i = 0; i < size - 1; i++) { + buffer[i] = buffer[i + 1]; + } + size--; + return removedItem; + } + + /** + * Removes and returns the element at the back of this list. + * This method has a worst-case runtime complexity of O(1), + * as it simply removes the element at the end of the buffer. + * + * @return the element at the back of this list + * @throws NoSuchElementException if this list is empty + */ + @Override + public E removeBack() { + if (isEmpty()) { + throw new NoSuchElementException("List is empty"); + } + E removedItem = buffer[size - 1]; + buffer[--size] = null; + return removedItem; + } + + /** + * Removes the first occurrence of the specified element from this list, if it is present. + * This method has a worst-case runtime complexity of O(n), + * where n is the number of elements in the list, because it may + * need to shift all existing elements after the removed element to the left. + * + * @param item the element to be removed from this list + */ + @Override + public void remove(E item) { + for (int i = 0; i < size; i++) { + if (buffer[i].equals(item)) { + for (int j = i; j < size - 1; j++) { + buffer[j] = buffer[j + 1]; + } + buffer[--size] = null; + return; + } + } + } + + /** + * Removes and returns the element at the specified index in this list. + * This method has a worst-case runtime complexity of O(n), + * where n is the number of elements in the list, because it may + * need to shift all existing elements after the specified index to the left. + * + * @param index the index of the element to be removed + * @return the element previously at the specified position + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public E remove(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index is out of bounds"); + } + E removedItem = buffer[index]; + for (int i = index; i < size - 1; i++) { + buffer[i] = buffer[i + 1]; + } + buffer[--size] = null; + return removedItem; + } + + /** + * Returns true if this list contains the specified element. + * This method has a worst-case runtime complexity of O(n), + * where n is the number of elements in the list, because it may + * need to iterate through all elements to find the specified element. + * + * @param item the element to be checked for containment in this list + * @return true if this list contains the specified element + */ + @Override + public boolean contains(E item) { + for (int i = 0; i < size; i++) { + if (buffer[i].equals(item)) { + return true; + } + } + return false; + } + + /** + * Returns true if this list contains no elements. + * This method has a runtime complexity of O(1). + * + * @return true if this list contains no elements + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the number of elements in this list. + * This method has a runtime complexity of O(1). + * + * @return the number of elements in this list + */ + @Override + public int size() { + return size; + } + + /** + * Resizes the internal buffer by doubling its capacity. + * This method has a worst-case runtime complexity of O(n), + * where n is the number of elements in the list, because it + * needs to copy all existing elements to the new buffer. + */ + private void resize() { + E[] newBuffer = (E[]) new Object[size * 2]; + for (int i = 0; i < size; i++) { + newBuffer[i] = buffer[i]; + } + buffer = newBuffer; + } + + /** + * Returns an iterator over the elements in this list. + * This method has a runtime complexity of O(1). + * + * @return an iterator over the elements in this list + */ + @Override + public Iterator iterator() { + return new ArrayListIterator(); + } + + private class ArrayListIterator implements Iterator { + private int index = 0; + + @Override + public boolean hasNext() { + return index < size; + } + + @Override + public E next() { + if (!hasNext()) { + throw new UnsupportedOperationException("No more elements in list"); + } + return buffer[index++]; + } + } +} \ No newline at end of file diff --git a/src/Bag.java b/src/Bag.java new file mode 100644 index 0000000..cec3c34 --- /dev/null +++ b/src/Bag.java @@ -0,0 +1,5 @@ +public interface Bag extends Iterable { + void add(Item item); + boolean isEmpty(); + int size(); +} diff --git a/src/LinkedBag.java b/src/LinkedBag.java new file mode 100644 index 0000000..17031f6 --- /dev/null +++ b/src/LinkedBag.java @@ -0,0 +1,94 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * LinkedBag represents a bag (or multiset) data structure implemented using a linked list. + * + * @param the type of elements stored in the stack + * @author Noah Lanctot + * @version 1.0 + */ +public class LinkedBag implements Bag { + + private Node first; + private int size; + + private static class Node { + private E item; + private Node next; + } + + /** + * Initializes an empty bag. + */ + public LinkedBag() { + first = null; + size = 0; + } + + /** + * Adds an item to the bag. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @param e the item to add + */ + @Override + public void add(E e) { + Node newNode = new Node<>(); + newNode.item = e; + newNode.next = first; + first = newNode; + size++; + } + + /** + * Checks whether the bag is empty. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return true if the bag is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the number of items in the bag. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return the number of items in the bag + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator to traverse the items in the bag. + * + * @return an iterator to traverse the items in the bag + */ + @Override + public Iterator iterator() { + return new BagIterator(); + } + + private class BagIterator implements Iterator { + private Node current = first; + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + E item = current.item; + current = current.next; + return item; + } + } +} \ No newline at end of file diff --git a/src/LinkedList.java b/src/LinkedList.java new file mode 100644 index 0000000..81b54b6 --- /dev/null +++ b/src/LinkedList.java @@ -0,0 +1,317 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Implementation of a singly linked list. + * + * @author Noah Lanctot + * @version 1.0 + * @param the type of elements in this list + */ +public class LinkedList implements List { + + private Node head; + private int size; + + /** + * Constructs an empty LinkedList. + */ + public LinkedList() { + head = null; + size = 0; + } + + private static class Node { + E data; + Node next; + + public Node(E data) { + this.data = data; + this.next = null; + } + } + + /** + * Adds the specified element to the front of this list. + * This method has a runtime complexity of O(1). + * + * @param item the element to be added to the front of this list + */ + @Override + public void addFront(E item) { + Node newNode = new Node<>(item); + newNode.next = head; + head = newNode; + size++; + } + + /** + * Adds the specified element to the back of this list. + * This method has a runtime complexity of O(n), + * where n is the number of elements in the list, because it + * may need to traverse the list to find the last node. + * + * @param item the element to be added to the back of this list + */ + @Override + public void addBack(E item) { + if (head == null) { + addFront(item); + } else { + Node newNode = new Node<>(item); + Node current = head; + while (current.next != null) { + current = current.next; + } + current.next = newNode; + size++; + } + } + + /** + * Adds the specified element at the specified index in this list. + * This method has a runtime complexity of O(n), + * where n is the number of elements in the list, because it + * may need to traverse the list to find the node before the specified index. + * + * @param index the index at which the specified element is to be inserted + * @param item the element to be inserted + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public void add(int index, E item) { + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException("Index is out of bounds"); + } + if (index == 0) { + addFront(item); + } else { + Node newNode = new Node<>(item); + Node current = head; + for (int i = 0; i < index - 1; i++) { + current = current.next; + } + newNode.next = current.next; + current.next = newNode; + size++; + } + } + + /** + * Returns the element at the specified index in this list. + * This method has a runtime complexity of O(n), + * where n is the index of the element to be retrieved, + * because it may need to traverse the list to find the node at the specified index. + * + * @param index the index of the element to return + * @return the element at the specified index in this list + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public E get(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index is out of bounds"); + } + Node current = head; + for (int i = 0; i < index; i++) { + current = current.next; + } + return current.data; + } + + /** + * Replaces the element at the specified index in this list with the specified element. + * This method has a runtime complexity of O(n), + * where n is the index of the element to be replaced, + * because it may need to traverse the list to find the node at the specified index. + * + * @param index the index of the element to replace + * @param item the element to be stored at the specified index + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public void set(int index, E item) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index is out of bounds"); + } + Node current = head; + for (int i = 0; i < index; i++) { + current = current.next; + } + current.data = item; + } + + /** + * Removes and returns the element at the front of this list. + * This method has a runtime complexity of O(1). + * + * @return the element at the front of this list + * @throws NoSuchElementException if this list is empty + */ + @Override + public E removeFront() { + if (isEmpty()) { + throw new NoSuchElementException("List is empty"); + } + E removedItem = head.data; + head = head.next; + size--; + return removedItem; + } + + /** + * Removes and returns the element at the back of this list. + * This method has a runtime complexity of O(n), + * where n is the number of elements in the list, because it + * may need to traverse the list to find the second-to-last node. + * + * @return the element at the back of this list + * @throws NoSuchElementException if this list is empty + */ + @Override + public E removeBack() { + if (isEmpty()) { + throw new NoSuchElementException("List is empty"); + } + if (size == 1) { + return removeFront(); + } + Node current = head; + while (current.next.next != null) { + current = current.next; + } + E removedItem = current.next.data; + current.next = null; + size--; + return removedItem; + } + + /** + * Removes the first occurrence of the specified element from this list, if it is present. + * This method has a runtime complexity of O(n), + * where n is the number of elements in the list, because it + * may need to traverse the list to find the specified element. + * + * @param item the element to be removed from this list + */ + @Override + public void remove(E item) { + if (isEmpty()) { + return; + } + if (head.data.equals(item)) { + removeFront(); + return; + } + Node current = head; + while (current.next != null) { + if (current.next.data.equals(item)) { + current.next = current.next.next; + size--; + return; + } + current = current.next; + } + } + + /** + * Removes and returns the element at the specified index in this list. + * This method has a runtime complexity of O(n), + * where n is the index of the element to be removed, + * because it may need to traverse the list to find the node before the specified index. + * + * @param index the index of the element to be removed + * @return the element previously at the specified position + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public E remove(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index is out of bounds"); + } + if (index == 0) { + return removeFront(); + } + Node current = head; + for (int i = 0; i < index - 1; i++) { + current = current.next; + } + E removedItem = current.next.data; + current.next = current.next.next; + size--; + return removedItem; + } + + /** + * Returns true if this list contains the specified element. + * This method has a runtime complexity of O(n), + * where n is the number of elements in the list, because it + * may need to traverse the list to find the specified element. + * + * @param item the element to be checked for containment in this list + * @return true if this list contains the specified element + */ + @Override + public boolean contains(E item) { + Node current = head; + while (current != null) { + if (current.data.equals(item)) { + return true; + } + current = current.next; + } + return false; + } + + /** + * Returns true if this list contains no elements. + * This method has a runtime complexity of O(1). + * + * @return true if this list contains no elements + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the number of elements in this list. + * This method has a runtime complexity of O(1). + * + * @return the number of elements in this list + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator over the elements in this list. + * This method has a runtime complexity of O(1). + * + * @return an iterator over the elements in this list + */ + @Override + public Iterator iterator() { + return new LinkedListIterator(); + } + + private class LinkedListIterator implements Iterator { + private Node current = head; + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException("No more elements in list"); + } + E data = current.data; + current = current.next; + return data; + } + } +} \ No newline at end of file diff --git a/src/LinkedQueue.java b/src/LinkedQueue.java new file mode 100644 index 0000000..10d16c4 --- /dev/null +++ b/src/LinkedQueue.java @@ -0,0 +1,116 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * LinkedQueue represents a queue data structure implemented using a linked list. + * + * @param the type of elements stored in the stack + * @author Noah Lanctot + * @version 1.0 + */ +public class LinkedQueue implements Queue { + + private Node first; + private Node last; + private int size; + + private static class Node { + private E item; + private Node next; + } + + /** + * Adds an item to the end of the queue. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @param item the item to enqueue + */ + @Override + public void enqueue(E item) { + Node newNode = new Node<>(); + newNode.item = item; + newNode.next = null; + + if (isEmpty()) { + first = newNode; + } else { + last.next = newNode; + } + + last = newNode; + size++; + } + + /** + * Removes and returns the item least recently added to this queue. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return the item least recently added + * @throws NoSuchElementException if the queue is empty + */ + @Override + public E dequeue() { + if (isEmpty()) { + throw new NoSuchElementException("Queue underflow"); + } + + E item = first.item; + first = first.next; + size--; + if (isEmpty()) { + last = null; + } + return item; + } + + /** + * Checks whether the queue is empty. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return true if the queue is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the number of items in the queue. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return the number of items in the queue + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator to traverse the items in the queue. + * + * @return an iterator to traverse the items in the queue + */ + @Override + public Iterator iterator() { + return new QueueIterator(); + } + + private class QueueIterator implements Iterator { + private Node current = first; + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + E item = current.item; + current = current.next; + return item; + } + } +} \ No newline at end of file diff --git a/src/LinkedStack.java b/src/LinkedStack.java new file mode 100644 index 0000000..c9e4792 --- /dev/null +++ b/src/LinkedStack.java @@ -0,0 +1,132 @@ +import java.util.Iterator; + +/** + * LinkedStack represents a stack data structure implemented using a linked list. + * + * @param the type of elements stored in the stack + * @author Noah Lanctot + * @version 1.0 + */ +public class LinkedStack implements Stack { + + private Node top; + private int size; + + private static class Node { + private E data; + private Node next; + + public Node(E data) { + this.data = data; + this.next = null; + } + } + + /** + * Initializes an empty stack. + */ + public LinkedStack() { + top = null; + size = 0; + } + + /** + * Adds an item to the top of the stack. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @param item the item to be added + */ + @Override + public void push(E item) { + Node newNode = new Node<>(item); + + newNode.next = top; + top = newNode; + size++; + } + + /** + * Removes and returns the item most recently added to this stack. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return the item most recently added + * @throws IllegalStateException if the stack is empty + */ + @Override + public E pop() { + if (isEmpty()) { + throw new IllegalStateException("Stack is empty"); + } + + E data = top.data; + top = top.next; + size--; + + return data; + } + + /** + * Returns the item most recently added to this stack without removing it. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return the item most recently added + * @throws IllegalStateException if the stack is empty + */ + @Override + public E peek() { + if (isEmpty()) { + throw new IllegalStateException("Stack is empty"); + } + + return top.data; + } + + /** + * Checks whether the stack is empty. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return true if the stack is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the number of items in the stack. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return the number of items in the stack + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator to traverse the items in the stack. + * + * @return an iterator to traverse the items in the stack + */ + @Override + public Iterator iterator() { + return new Iterator() { + private Node current = top; + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public E next() { + if (!hasNext()) { + throw new IllegalStateException("No more elements in the stack"); + } + E data = current.data; + current = current.next; + return data; + } + }; + } +} \ No newline at end of file diff --git a/src/Main.java b/src/Main.java index 8f8f984..503e72c 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,10 +1,5 @@ -//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!"); - + System.out.println("Hello World!"); } } \ No newline at end of file diff --git a/src/ResizingArrayStack.java b/src/ResizingArrayStack.java new file mode 100644 index 0000000..ec0ce0f --- /dev/null +++ b/src/ResizingArrayStack.java @@ -0,0 +1,133 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Implementation of a stack using a resizing array. + * + * @param the type of elements stored in the stack + * @author Noah Lanctot + * @version 1.0 + */ +public class ResizingArrayStack implements Stack { + private E[] array; + private int size; + + /** + * Initializes an empty stack with an initial capacity of 10. + */ + public ResizingArrayStack() { + array = (E[]) new Object[10]; + size = 0; + } + + /** + * Resizes the array to the given capacity. + * + * @param capacity the new capacity of the array + */ + private void resize(int capacity) { + E[] newArray = (E[]) new Object[capacity]; + for (int i = 0; i < size; i++) { + newArray[i] = array[i]; + } + array = newArray; + } + + /** + * Adds an item to the top of the stack. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @param item the item to be added + */ + @Override + public void push(E item) { + if (size == array.length) { + resize(2 * array.length); + } + array[size++] = item; + } + + /** + * Removes and returns the item most recently added to this stack. + * Time complexity: O(1) (amortized), O(N) (worst-case when resizing) + * + * @return the item most recently added + * @throws NoSuchElementException if the stack is empty + */ + @Override + public E pop() { + if (isEmpty()) { + throw new NoSuchElementException("Stack underflow"); + } + E item = array[--size]; + array[size] = null; + if (size > 0 && size == array.length / 4) { + resize(array.length / 2); + } + return item; + } + + /** + * Returns the item most recently added to this stack without removing it. + * Time complexity: O(1) + * + * @return the item most recently added + * @throws NoSuchElementException if the stack is empty + */ + @Override + public E peek() { + if (isEmpty()) { + throw new NoSuchElementException("Stack underflow"); + } + return array[size - 1]; + } + + /** + * Checks whether the stack is empty. + * Time complexity: O(1) + * + * @return true if the stack is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the number of items in the stack. + * Time complexity: O(1) + * + * @return the number of items in the stack + */ + @Override + public int size() { + return size; + } + + /** + * Returns an iterator to traverse the items in the stack. + * + * @return an iterator to traverse the items in the stack + */ + @Override + public Iterator iterator() { + return new ArrayIterator(); + } + + private class ArrayIterator implements Iterator { + private int index = size - 1; + + @Override + public boolean hasNext() { + return index >= 0; + } + + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return array[index--]; + } + } +} \ No newline at end of file