diff --git a/IntListReview.iml b/IntListReview.iml index c90834f..ff79d70 100644 --- a/IntListReview.iml +++ b/IntListReview.iml @@ -7,5 +7,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ArrayIntList.java b/src/ArrayIntList.java new file mode 100644 index 0000000..5d195db --- /dev/null +++ b/src/ArrayIntList.java @@ -0,0 +1,322 @@ +import java.lang.reflect.Array; +import java.nio.Buffer; +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class ArrayIntList implements IntList{ + // Internal private representation + private int[] buffer; + private int size; // Num of positions used in the buffer + private final static int INITIAL_CAPACITY = 10; + + public ArrayIntList() { + buffer = new int[INITIAL_CAPACITY]; + size = 0; + } + + + /** + * Prepends (inserts) the specified value at the front of the list (at index 0). + * Shifts the value currently at the front of the list (if any) and any + * subsequent values to the right. + * + * Speed = Relatively SLow, Linear Time O(size), has to shift size items right + * + * @param value value to be inserted + */ + @Override + public void addFront(int value) { + // check if full + if (size == buffer.length){ + resize(2 * buffer.length); + } + // Open a spot at index 0 where value will be saved + // Shift everything over to the right by 1 position + for(int i = size; i > 0; i--){ + buffer[i] = buffer[i-1]; + } + + // Put the value at position [0] + buffer[0] = value; + size++; + } + + + /** + * Appends (inserts) the specified value at the back of the list (at index size()-1). + * + * Speed = Fast, Constant Time if no Resize 0(1) + * Can be Slow if resize is involved + * + * @param value value to be inserted + */ + @Override + public void addBack(int value) { + // Check to see if we still have the capacity in buffer + if (size == buffer.length) { + // If the size matches the capacity, then I know I'm "full" and I need to resize + // ( create a new larger buffer and copy the values over from the older smaller buffer) + + // Make the newSize twice the existing capacity + resize(2 * buffer.length); + } + + buffer[size] = value; + size++; + } + + /** + * Inserts the specified value at the specified position in this list. + * Shifts the value currently at that position (if any) and any subsequent + * values to the right. + * + * Speed = Depends on index. Can be as slow as add front or as fast as add back. + * Worst case speed = add at index 0 (Linear) and resize is needed + * Best case speed = add at index (size) (Constant) and no resize needed + * + * @param index index at which the specified value is to be inserted + * @param value value to be inserted + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public void add(int index, int value) { + if (index > size){ + throw new IndexOutOfBoundsException("Index is longer than the length!"); + } + + // check if full + if (size == buffer.length){ + resize(2 * buffer.length); + } + + for (int i = size; i > index; i--){ + buffer[i] = buffer[i-1]; + } + + buffer[index] = value; + size++; + } + + /** + * Removes the value located at the front of the list + * (at index 0), if it is present. + * Shifts any subsequent values to the left. + * + * Speed = Slow, Linear Time O(size) / O(n) + */ + @Override + public void removeFront() { + if (size == 0){ + throw new IllegalStateException("Array is empty!"); + } + for(int i = 0; i < size; i++){ + buffer[i] = buffer[i+1]; + } + size--; + } + + /** + * Removes the value located at the back of the list + * (at index size()-1), if it is present. + * + * Speed = fast and Constant O(1) + */ + @Override + public void removeBack() { + if (size == 0){ + throw new IllegalStateException("Already empty!"); + } + buffer[--size] = 0; + } + + /** + * Removes the value at the specified position in this list. + * Shifts any subsequent values to the left. Returns the value + * that was removed from the list. + * + * Speed = Depends on index. Can be as slow as remove front or as fast as remove back. + * Worst case speed = remove at index 0 (Linear) with a shift of numbers left + * Best case speed = remove at index (size) (Constant) + * + * @param index the index of the value to be removed + * @return the value previously at the specified position + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public int remove(int index) { + if (index > size){ + throw new IndexOutOfBoundsException("Index must be in range"); + } + + int r = buffer[index]; + for(int i = 0; i < size; i++){ + if (i >= index){ + buffer[i] = buffer[i+1]; + } + } + size--; + return r; + } + + /** + * Returns the value at the specified position in the list. + * + * Speed = Fast, Constant Time 0(1) + * + * @param index index of the value to return + * @return the value at the specified position in this list + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public int get(int index) { + if (index < size){ + return buffer[index]; + }else{ + throw new IndexOutOfBoundsException("Index is out of Range!"); + } + } + + + /** + * Returns true if this list contains the specified value. + * + * Speed = depends on if value exists or not. + * Worst case = Linear time O(size) and value is not in list or the last index + * Best case = value = index 0 + * + * @param value value whose presence in this list is to be searched for + * @return true if this list contains the specified value + */ + @Override + public boolean contains(int value) { + for(int i = 0; i < size; i++){ + if (buffer[i] == value){ + return true; + } + } + return false; + } + + /** + * Returns the index of the first occurrence of the specified value + * in this list, or -1 if this list does not contain the value. + * + * Speed = depends on if value exists or not. + * Worst case = Linear time O(size) and value is not in list or the last index + * Best case = value = index 0 + * + * @param value value to search for + * @return the index of the first occurrence of the specified value in this list + * or -1 if this list does not contain the value + */ + @Override + public int indexOf(int value) { + for(int i = 0; i < size; i++){ + if (buffer[i] == value){ + return i; + } + } + return -1; + } + + /** + * Returns true if this list contains no values. + * + * @return true if this list contains no values + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the number of values in this list. + * + * @return the number of values in this list + */ + @Override + public int size() { + return size; + } + + /** + * Removes all the values from this list. + * The list will be empty after this call returns. + */ + @Override + public void clear() { + // Shrink the list back down to the original creation size + buffer = new int[INITIAL_CAPACITY]; + size = 0; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new ArrayIntListIterator(); + } + + + // Speed = O(n) or O(size) - Linear Time because you have to visit every item + @Override + public String toString() { + if ( size == 0 ){ + return "[]"; + } + StringBuilder sb = new StringBuilder(); + sb.append("["); + + for (int i = 0; i < size; i++){ + sb.append(buffer[i]); + sb.append(i == size-1 ? "" : ", "); // Only append the comma if it's not the last index + } + + sb.append("]"); + return sb.toString(); + } + + // Speed = "Slow", Linear Time O(n) + // Depends on size of array because it copies old array into new array + private void resize(int newSize) { + // create a new array that is of the new size + int[] temp = new int[newSize]; + + // copy over values from the existing buffer + for (int i = 0; i < size; i++) { + temp[i] = buffer[i]; + } + + // Make the switchover + buffer = temp; + } + + // Nested or inner class (helper class) + public class ArrayIntListIterator implements Iterator{ + private int currentPosition; + + public ArrayIntListIterator(){ + currentPosition = 0; + } + + @Override + public boolean hasNext() { + return currentPosition < size(); + } + + @Override + public Integer next() { + // Just to be safe - make sure there is a next + if (!hasNext()) { + throw new NoSuchElementException(); + } + int value = get(currentPosition); + currentPosition++; + return value; + } + } + +} // End of ArrayIntList diff --git a/src/ArrayIntListTest.java b/src/ArrayIntListTest.java new file mode 100644 index 0000000..bdcf2ac --- /dev/null +++ b/src/ArrayIntListTest.java @@ -0,0 +1,535 @@ +import static org.junit.jupiter.api.Assertions.*; + +class ArrayIntListTest { + + // addFront() Tests + + @org.junit.jupiter.api.Test + void addFrontWithEmptyList() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(42); + assertEquals(theList.get(0), 42); + } + @org.junit.jupiter.api.Test + void addFrontWithNonEmptyList() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(42); + theList.addFront(22); + theList.addFront(8); + theList.addFront(99); + assertEquals(theList.get(0), 99); + } + + @org.junit.jupiter.api.Test + void addFrontWithResize() { + ArrayIntList theList = new ArrayIntList(); + for(int i=0; i < 10; i++){ + theList.addFront(i); + } + theList.addFront(42); + assertEquals(theList.get(0), 42); + } + + @org.junit.jupiter.api.Test + void addFrontWithMultipleResizes() { + ArrayIntList theList = new ArrayIntList(); + for(int i=0; i < 100000; i++){ + theList.addFront(i); + } + theList.addFront(42); + assertEquals(theList.get(0), 42); + } + + // addBack() Tests + @org.junit.jupiter.api.Test + void addBackWithEmptyList() { + ArrayIntList theList = new ArrayIntList(); + theList.addBack(42); + assertEquals(theList.get(0), 42); + } + + @org.junit.jupiter.api.Test + void addBackWithNonEmptyList() { + ArrayIntList theList = new ArrayIntList(); + theList.addBack(1); + theList.addBack(2); + theList.addBack(3); + theList.addBack(42); + assertEquals(theList.get(theList.size()-1), 42); + } + + @org.junit.jupiter.api.Test + void addBackWithResize() { + ArrayIntList theList = new ArrayIntList(); + for(int i=0; i < 10; i++){ + theList.addBack(i); + } + theList.addBack(42); + assertEquals(theList.get(theList.size()-1), 42); + } + + @org.junit.jupiter.api.Test + void addBackWithMultipleResizes() { + ArrayIntList theList = new ArrayIntList(); + for(int i=0; i < 1000000; i++){ + theList.addBack(i); + } + theList.addBack(42); + assertEquals(theList.get(theList.size()-1), 42); + } + + + + // add() Tests + + + + @org.junit.jupiter.api.Test + void addWithEmptyList() { + ArrayIntList theList = new ArrayIntList(); + + theList.add(0, 42); + assertEquals(theList.get(0), 42); + } + @org.junit.jupiter.api.Test + void addWithNonEmptyListToMiddle() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(50); + theList.addFront(24); + theList.addFront(15); + theList.addFront(50); + theList.addFront(22); + theList.addFront(15); + + theList.add(2, 15); + assertEquals(theList.get(2), 15); + } + + @org.junit.jupiter.api.Test + void addWithNonEmptyListToBack() { + ArrayIntList theList = new ArrayIntList(); + theList.addBack(50); + theList.addBack(24); + theList.addBack(15); + theList.addBack(50); + theList.addBack(22); + theList.addBack(15); + + theList.add(theList.size()-1, 15); + assertEquals(theList.get(theList.size()-1), 15); + } + @org.junit.jupiter.api.Test + void addWithIndexOutOfRange() { + ArrayIntList theList = new ArrayIntList(); + + theList.addFront(42); + theList.addFront(55); + theList.addFront(80); + + assertThrows(IndexOutOfBoundsException.class, ()->{theList.add(5, 2);}); + } + + @org.junit.jupiter.api.Test + void addWithResize() { + ArrayIntList theList = new ArrayIntList(); + for(int i=0; i < 10; i++){ + theList.add(i, i*2); + } + theList.add(theList.size(), 42); + assertEquals(theList.get(theList.size()-1), 42); + } + + + + // removeFront() Tests + + + @org.junit.jupiter.api.Test + void removeFront() { + ArrayIntList theList = new ArrayIntList(); + + theList.addFront(42); + theList.addFront(55); + theList.addFront(72); + theList.addFront(80); + theList.addFront(24); + theList.removeFront(); + assertEquals(theList.get(0), 80); + } + + @org.junit.jupiter.api.Test + void removeFrontMultipleTimes() { + ArrayIntList theList = new ArrayIntList(); + + theList.addFront(42); + theList.addFront(55); + theList.addFront(72); + theList.addFront(80); + theList.addFront(24); + theList.removeFront(); + theList.removeFront(); + theList.removeFront(); + theList.removeFront(); + assertEquals(theList.get(0), 42); + } + + @org.junit.jupiter.api.Test + void removeFrontEmptyList() { + ArrayIntList theList = new ArrayIntList(); + + assertThrows(IllegalStateException.class, theList::removeFront); + } + + @org.junit.jupiter.api.Test + void removeFrontAfterResize() { + ArrayIntList theList = new ArrayIntList(); + + for(int i=0; i < 100; i++){ + theList.addBack(i); + } + theList.removeFront(); + + assertEquals(theList.get(0), 1); + } + + + + // removeBack() Tests + + + @org.junit.jupiter.api.Test + void removeBackFromEmptyList() { + ArrayIntList theList = new ArrayIntList(); + + assertThrows(IllegalStateException.class, theList::removeBack); + } + + @org.junit.jupiter.api.Test + void removeBackFromSingleItemList() { + ArrayIntList theList = new ArrayIntList(); + + theList.addBack(50); + theList.removeBack(); + assertEquals(theList.size(), 0); + } + + @org.junit.jupiter.api.Test + void removeBackFromListOf10() { + ArrayIntList theList = new ArrayIntList(); + + // Fill list with 10 items [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + for(int i=0; i < 10; i++){ + theList.addBack(i); + } + + // Remove the item from the back + theList.removeBack(); + + String out = theList.toString(); + assertEquals(out, "[0, 1, 2, 3, 4, 5, 6, 7, 8]"); + } + + + + // remove() Tests + + + @org.junit.jupiter.api.Test + void removeFromMiddle() { + ArrayIntList theList = new ArrayIntList(); + // Add 100 numbers to the list + for(int i = 0; i < 100; i++){ + theList.addBack(i); + } + assertEquals(theList.remove(5), 5); + } + + @org.junit.jupiter.api.Test + void removeFromBeginning() { + ArrayIntList theList = new ArrayIntList(); + // Add 100 numbers to the list + for(int i = 0; i < 100; i++){ + theList.addBack(i); + } + assertEquals(theList.remove(0), 0); + } + + @org.junit.jupiter.api.Test + void removeFromEnd() { + ArrayIntList theList = new ArrayIntList(); + // Add 100 numbers to the list + for(int i = 0; i < 100; i++){ + theList.addBack(i); + } + assertEquals(theList.remove(theList.size()-1), 99); + } + + + + // get() Tests + + + @org.junit.jupiter.api.Test + void getFromEmptyList() { + ArrayIntList theList = new ArrayIntList(); + assertThrows(IndexOutOfBoundsException.class, ()->{ + theList.get(0); + }); + } + + @org.junit.jupiter.api.Test + void getFromSingleItemList() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(50); + assertEquals(theList.get(0), 50); + } + + @org.junit.jupiter.api.Test + void getFromMultiItemList() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(50); + theList.addFront(22); + theList.addBack(78); + theList.addBack(45); + theList.addBack(14); + assertEquals(theList.get(2), 78); + } + + @org.junit.jupiter.api.Test + void getFromBack() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(50); + theList.addFront(22); + theList.addFront(15); + theList.addFront(66); + assertEquals(theList.get(theList.size()-1), 50); + } + + // contains() Tests + @org.junit.jupiter.api.Test + void containsWithEmptyList() { + ArrayIntList theList = new ArrayIntList(); + assertFalse(theList.contains(5)); + } + + @org.junit.jupiter.api.Test + void containsWithSingleItem() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(5); + assertTrue(theList.contains(5)); + } + + @org.junit.jupiter.api.Test + void containsWithMultiItem() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(5); + theList.addFront(10); + theList.addFront(15); + theList.addFront(20); + assertTrue(theList.contains(15)); + } + + + + // indexOf() Tests + + + @org.junit.jupiter.api.Test + void indexOfEmptyList() { + ArrayIntList theList = new ArrayIntList(); + assertEquals(theList.indexOf(0), -1); + } + + @org.junit.jupiter.api.Test + void indexOfSingleItem() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(10); + assertEquals(theList.indexOf(10), 0); + } + + @org.junit.jupiter.api.Test + void indexOfFullList() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(10); + theList.addFront(22); + theList.addFront(36); + theList.addFront(78); + theList.addFront(49); + theList.addFront(99); + assertEquals(theList.indexOf(78), 2); + } + + @org.junit.jupiter.api.Test + void indexOfItemAtEnd() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(10); + theList.addFront(56); + theList.addFront(99); + theList.addFront(28); + theList.addFront(75); + theList.addFront(73); + theList.addFront(58); + assertEquals(theList.indexOf(10), theList.size()-1); + } + + + // isEmpty() Tests + + + @org.junit.jupiter.api.Test + void isEmptyWithNoItems() { + ArrayIntList theList = new ArrayIntList(); + + assertTrue(theList.isEmpty()); + } + + @org.junit.jupiter.api.Test + void isEmptyWithSingleItem() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(10); + + assertFalse(theList.isEmpty()); + } + + @org.junit.jupiter.api.Test + void isEmptyWithMultipleItems() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(10); + theList.addFront(22); + theList.addFront(76); + theList.addFront(48); + theList.addFront(90); + + assertFalse(theList.isEmpty()); + } + + @org.junit.jupiter.api.Test + void isEmptyAfterRemoval() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(10); + theList.addFront(22); + theList.removeFront(); + theList.removeFront(); + + assertTrue(theList.isEmpty()); + } + + + + // size() Tests + + + @org.junit.jupiter.api.Test + void sizeWhileEmpty() { + ArrayIntList theList = new ArrayIntList(); + + assertEquals(theList.size(), 0); + } + + @org.junit.jupiter.api.Test + void sizeWithSingleItem() { + ArrayIntList theList = new ArrayIntList(); + + theList.addFront(55); + + assertEquals(theList.size(), 1); + } + + @org.junit.jupiter.api.Test + void sizeWithMultipleItems() { + ArrayIntList theList = new ArrayIntList(); + + for(int i=0; i< 100; i++){ + theList.addBack(i); + } + + assertEquals(theList.size(), 100); + } + + + + // clear() Tests + + + @org.junit.jupiter.api.Test + void clearWithItemsInList() { + ArrayIntList theList = new ArrayIntList(); + + theList.addFront(5); + theList.addFront(50); + theList.addFront(24); + + theList.clear(); + assertEquals(theList.size(), 0); + } + + @org.junit.jupiter.api.Test + void clearWithEmptyList() { + ArrayIntList theList = new ArrayIntList(); + + theList.clear(); + assertEquals(theList.size(), 0); + } + + @org.junit.jupiter.api.Test + void clearAfterAddThenRemoveList() { + ArrayIntList theList = new ArrayIntList(); + + theList.addFront(5); + theList.addFront(50); + theList.removeFront(); + theList.removeFront(); + + theList.clear(); + assertEquals(theList.size(), 0); + } + + + + // Iterator() tests + + + @org.junit.jupiter.api.Test + void iterator() { + ArrayIntList theList = new ArrayIntList(); + theList.addFront(5); + theList.addFront(10); + theList.addFront(15); + theList.addFront(20); + + int i = 0; + for(int n : theList){ + assertEquals(n, theList.get(i)); + i++; + } + } + + + + // toString() Tests + + + @org.junit.jupiter.api.Test + void testToStringWithSingleItem() { + ArrayIntList theList = new ArrayIntList(); + + theList.addFront(5); + assertEquals(theList.toString(), "[5]"); + } + + @org.junit.jupiter.api.Test + void testToStringWithMultipleItems() { + ArrayIntList theList = new ArrayIntList(); + + theList.addFront(5); + theList.addFront(50); + assertEquals(theList.toString(), "[50, 5]"); + } + + @org.junit.jupiter.api.Test + void testToStringWithEmptyList() { + ArrayIntList theList = new ArrayIntList(); + + assertEquals(theList.toString(), "[]"); + } +} \ No newline at end of file diff --git a/src/LinkedIntList.java b/src/LinkedIntList.java new file mode 100644 index 0000000..34ed692 --- /dev/null +++ b/src/LinkedIntList.java @@ -0,0 +1,357 @@ +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class LinkedIntList implements IntList{ + // Helper inner/nested class + public class Node { + int data; // Hold the data value + Node next; // Holds the address of the next node + + public Node(){ + data = 0; + next = null; + } + + // T = 2 is O(n) constant time + public Node(int data, Node next){ + this.data = data; + this.next = next; + } + // End of class node + } + + // Fields for LinkedIntList class + private Node head; // Address of the first node in list + private int size; // Number of nodes/items in list + + + // T = 2 is O(1) constant time + public LinkedIntList(){ + head = null; + size = 0; + } + + + /** + * Prepends (inserts) the specified value at the front of the list (at index 0). + * Shifts the value currently at the front of the list (if any) and any + * subsequent values to the right. + * + * T = 7 is O(1) constant time + * + * @param value value to be inserted + */ + @Override + public void addFront(int value) { + head = new Node(value, head); + size++; + } + + /** + * Appends (inserts) the specified value at the back of the list (at index size()-1). + * + * If list is empty, (if statement) then T = 5 is O(1) constant time + * If list is not empty, (else statement) then T = (2 * size) + 6 OR T = 2n + 6 which is O(n) linear time + * + * @param value value to be inserted + */ + @Override + public void addBack(int value) { + // If the list is empty + if (head == null){ + head = new Node(value, null); + + }else{ + // If the list is not empty + Node current = head; + + // Loop and stop on last node in list (But not all the way to null) + while (current.next != null){ + // move current forward + current = current.next; + } + // When I am here, current is referencing the last node + current.next = new Node(value, null); + } + // Increase the size of the list + size++; + } + + /** + * Inserts the specified value at the specified position in this list. + * Shifts the value currently at that position (if any) and any subsequent + * values to the right. + * + * @param index index at which the specified value is to be inserted + * @param value value to be inserted + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public void add(int index, int value) { + if (index > size){ + throw new IndexOutOfBoundsException("Index is longer than the length!"); + } + if (index == 0){ + head = new Node(value, null); + }else{ + Node newNode = new Node(value, null); + Node current = head; + + // Traverse to the node before the specified index + for (int i = 0; i < index - 1; i++) { + current = current.next; + } + + // Insert the new node in between + newNode.next = current.next; + current.next = newNode; + + + } + size++; + } + + /** + * Removes the value located at the front of the list + * (at index 0), if it is present. + * Shifts any subsequent values to the left. + */ + @Override + public void removeFront() { + if (size == 0){ + throw new IllegalStateException("List is empty!"); + } + if (head != null) { + Node current = head; + if (current.next != null){ + head = current.next; + }else{ + head = null; + } + size--; + } + } + + /** + * Removes the value located at the back of the list + * (at index size()-1), if it is present. + */ + @Override + public void removeBack() { + if (size == 0){ + throw new IllegalStateException("List is empty!"); + } + if (head != null){ + Node current = head; + // Check if there is a next + if (current.next != null){ + while (current.next.next != null){ + current = current.next; + } + current.next = null; + }else{ + head = null; + } + size--; + } + } + + /** + * Removes the value at the specified position in this list. + * Shifts any subsequent values to the left. Returns the value + * that was removed from the list. + * + * @param index the index of the value to be removed + * @return the value previously at the specified position + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public int remove(int index) { + if (size == 0){ + throw new IndexOutOfBoundsException("Index is out of range!"); + } + Node current = head; + for (int i = 0; i <= index; i++){ + if (i == index){ + Node removed = current; + current = current.next; + size--; + return removed.data; + } + if (current.next != null){ + current = current.next; + } + } + return -1; + } + + /** + * Returns the value at the specified position in the list. + * + * O(n) linear - to get an item at an index. I have to start at the head + * and walk up to the size poisitons over + * + * @param index index of the value to return + * @return the value at the specified position in this list + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public int get(int index) { + if (size == 0 || index > size){ + throw new IndexOutOfBoundsException("The index is out of bounds"); + } + Node current = head; + for (int i = 0; i <= index; i++){ + if (i == index){ + return current.data; + } + if (current.next != null){ + current = current.next; + } + } + return -1; + } + + /** + * Returns true if this list contains the specified value. + * + * @param value value whose presence in this list is to be searched for + * @return true if this list contains the specified value + */ + @Override + public boolean contains(int value) { + Node current = head; + while(current != null){ + if(current.data == value){ + return true; + } + current = current.next; + } + return false; + } + + /** + * Returns the index of the first occurrence of the specified value + * in this list, or -1 if this list does not contain the value. + * + * @param value value to search for + * @return the index of the first occurrence of the specified value in this list + * or -1 if this list does not contain the value + */ + @Override + public int indexOf(int value) { + int i = 0; + Node current = head; + while(current != null){ + if (current.data == value){ + return i; + } + current = current.next; + i++; + } + return -1; + } + + /** + * Returns true if this list contains no values. + * + * @return true if this list contains no values + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the number of values in this list. + * + * @return the number of values in this list + */ + @Override + public int size() { + return size; + } + + /** + * Removes all the values from this list. + * The list will be empty after this call returns. + */ + @Override + public void clear() { + head = null; + size = 0; + } + + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + return new LinkedIntListIterator(); + } + + // helper method (not required, but nice example + public void print() { + // Create a temp variable (almost like an index i) + // Copy in the address from head and save it + Node current = head; + + while (current != null){ + // print the value inside the node + System.out.println(current.data); + + // go to the next node + current = current.next; + } + } + + @Override + public String toString(){ + if (head == null) { + // If list is empty, indicate with [] + return "[]"; + } + + // If I got here, the list is not empty for sure + StringBuilder sb = new StringBuilder(); + sb.append("["); + + Node current = head; + while (current.next != null){ + sb.append(current.data); + sb.append(", "); + + current = current.next; + } + + // add the last node + sb.append(current.data); + sb.append("]"); + return sb.toString(); + } + + + // Nested or inner class (helper class) + public class LinkedIntListIterator implements Iterator{ + private Node current; // holds address of current node + + public LinkedIntListIterator(){ + // Start the current position at the first node in the list + current = head; + } + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public Integer next() { + int result = current.data; + current = current.next; + return result; + } + } +} diff --git a/src/LinkedIntListTest.java b/src/LinkedIntListTest.java new file mode 100644 index 0000000..852d7c3 --- /dev/null +++ b/src/LinkedIntListTest.java @@ -0,0 +1,452 @@ +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class LinkedIntListTest { + + // addFront() tests + + + @Test + void addFrontWithEmptyList() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(25); + assertEquals(theList.get(0), 25); + } + + @Test + void addFrontWithSingleItemList() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(40); + theList.addFront(4); + assertEquals(theList.get(0), 4); + } + + @Test + void addFrontWithMultiItemList() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(25); + theList.addFront(40); + theList.addFront(4); + theList.addFront(88); + assertEquals(theList.get(0), 88); + } + + + + // addBack() tests + + + + @Test + void addBackWithEmptyList() { + LinkedIntList theList = new LinkedIntList(); + theList.addBack(25); + assertEquals(theList.get(0), 25); + } + + @Test + void addBackWithSingleItemList() { + LinkedIntList theList = new LinkedIntList(); + theList.addBack(50); + theList.addBack(30); + assertEquals(theList.get(theList.size()-1), 30); + } + + @Test + void addBackWithMultiItemList() { + LinkedIntList theList = new LinkedIntList(); + theList.addBack(50); + theList.addBack(30); + theList.addBack(23); + theList.addBack(88); + assertEquals(theList.get(theList.size()-1), 88); + } + + + + // add() Tests + + + @org.junit.jupiter.api.Test + void addWithEmptyList() { + LinkedIntList theList = new LinkedIntList(); + + theList.add(0, 42); + assertEquals(theList.get(0), 42); + } + @org.junit.jupiter.api.Test + void addWithNonEmptyListToMiddle() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(50); + theList.addFront(24); + theList.addFront(15); + theList.addFront(50); + theList.addFront(22); + theList.addFront(15); + + theList.add(2, 15); + assertEquals(theList.get(2), 15); + } + + @org.junit.jupiter.api.Test + void addWithNonEmptyListToBack() { + LinkedIntList theList = new LinkedIntList(); + theList.addBack(50); + theList.addBack(24); + theList.addBack(15); + theList.addBack(50); + theList.addBack(22); + theList.addBack(15); + + theList.add(theList.size()-1, 15); + assertEquals(theList.get(theList.size()-1), 15); + } + @org.junit.jupiter.api.Test + void addWithIndexOutOfRange() { + LinkedIntList theList = new LinkedIntList(); + + theList.addFront(42); + theList.addFront(55); + theList.addFront(80); + + assertThrows(IndexOutOfBoundsException.class, ()->{theList.add(5, 2);}); + } + + + + // removeFront() Tests + + + @org.junit.jupiter.api.Test + void removeFront() { + LinkedIntList theList = new LinkedIntList(); + + theList.addFront(42); + theList.addFront(55); + theList.addFront(72); + theList.addFront(80); + theList.addFront(24); + theList.removeFront(); + assertEquals(theList.get(0), 80); + } + + @org.junit.jupiter.api.Test + void removeFrontMultipleTimes() { + LinkedIntList theList = new LinkedIntList(); + + theList.addFront(42); + theList.addFront(55); + theList.addFront(72); + theList.addFront(80); + theList.addFront(24); + theList.removeFront(); + theList.removeFront(); + theList.removeFront(); + theList.removeFront(); + assertEquals(theList.get(0), 42); + } + + @org.junit.jupiter.api.Test + void removeFrontEmptyList() { + LinkedIntList theList = new LinkedIntList(); + + assertThrows(IllegalStateException.class, theList::removeFront); + } + + + + // removeBack() Tests + + + @org.junit.jupiter.api.Test + void removeBackFromEmptyList() { + LinkedIntList theList = new LinkedIntList(); + + assertThrows(IllegalStateException.class, theList::removeBack); + } + + @org.junit.jupiter.api.Test + void removeBackFromSingleItemList() { + LinkedIntList theList = new LinkedIntList(); + + theList.addBack(50); + theList.removeBack(); + assertEquals(theList.size(), 0); + } + + @org.junit.jupiter.api.Test + void removeBackFromListOf10() { + LinkedIntList theList = new LinkedIntList(); + + // Fill list with 10 items [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + for(int i=0; i < 10; i++){ + theList.addBack(i); + } + + // Remove the item from the back + theList.removeBack(); + + String out = theList.toString(); + assertEquals(out, "[0, 1, 2, 3, 4, 5, 6, 7, 8]"); + } + + + + // remove() Tests + + + @org.junit.jupiter.api.Test + void removeFromMiddle() { + LinkedIntList theList = new LinkedIntList(); + // Add 100 numbers to the list + for(int i = 0; i < 100; i++){ + theList.addBack(i); + } + assertEquals(theList.remove(5), 5); + } + + @org.junit.jupiter.api.Test + void removeFromBeginning() { + LinkedIntList theList = new LinkedIntList(); + // Add 100 numbers to the list + for(int i = 0; i < 100; i++){ + theList.addBack(i); + } + assertEquals(theList.remove(0), 0); + } + + @org.junit.jupiter.api.Test + void removeFromEnd() { + LinkedIntList theList = new LinkedIntList(); + // Add 100 numbers to the list + for(int i = 0; i < 100; i++){ + theList.addBack(i); + } + assertEquals(theList.remove(theList.size()-1), 99); + } + + + + // get() Tests + + + @org.junit.jupiter.api.Test + void getFromEmptyList() { + LinkedIntList theList = new LinkedIntList(); + assertThrows(IndexOutOfBoundsException.class, ()->{ + theList.get(0); + }); + } + + @org.junit.jupiter.api.Test + void getFromSingleItemList() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(50); + assertEquals(theList.get(0), 50); + } + + @org.junit.jupiter.api.Test + void getFromMultiItemList() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(50); + theList.addFront(22); + theList.addBack(78); + theList.addBack(45); + theList.addBack(14); + assertEquals(theList.get(2), 78); + } + + @org.junit.jupiter.api.Test + void getFromBack() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(50); + theList.addFront(22); + theList.addFront(15); + theList.addFront(66); + assertEquals(theList.get(theList.size()-1), 50); + } + + + + // contains() Tests + + + @org.junit.jupiter.api.Test + void containsWithEmptyList() { + LinkedIntList theList = new LinkedIntList(); + assertFalse(theList.contains(5)); + } + + @org.junit.jupiter.api.Test + void containsWithSingleItem() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(5); + assertTrue(theList.contains(5)); + } + + @org.junit.jupiter.api.Test + void containsWithMultiItem() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(5); + theList.addFront(10); + theList.addFront(15); + theList.addFront(20); + assertTrue(theList.contains(15)); + } + + + // indexOf() Tests + + + @org.junit.jupiter.api.Test + void indexOfEmptyList() { + LinkedIntList theList = new LinkedIntList(); + assertEquals(theList.indexOf(0), -1); + } + + @org.junit.jupiter.api.Test + void indexOfSingleItem() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(10); + assertEquals(theList.indexOf(10), 0); + } + + @org.junit.jupiter.api.Test + void indexOfFullList() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(10); + theList.addFront(22); + theList.addFront(36); + theList.addFront(78); + theList.addFront(49); + theList.addFront(99); + assertEquals(theList.indexOf(78), 2); + } + + @org.junit.jupiter.api.Test + void indexOfItemAtEnd() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(10); + theList.addFront(56); + theList.addFront(99); + theList.addFront(28); + theList.addFront(75); + theList.addFront(73); + theList.addFront(58); + assertEquals(theList.indexOf(10), theList.size()-1); + } + + + + // isEmpty() Tests + + + @org.junit.jupiter.api.Test + void isEmptyWithNoItems() { + LinkedIntList theList = new LinkedIntList(); + + assertTrue(theList.isEmpty()); + } + + @org.junit.jupiter.api.Test + void isEmptyWithSingleItem() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(10); + + assertFalse(theList.isEmpty()); + } + + @org.junit.jupiter.api.Test + void isEmptyWithMultipleItems() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(10); + theList.addFront(22); + theList.addFront(76); + theList.addFront(48); + theList.addFront(90); + + assertFalse(theList.isEmpty()); + } + + @org.junit.jupiter.api.Test + void isEmptyAfterRemoval() { + LinkedIntList theList = new LinkedIntList(); + theList.addFront(10); + theList.addFront(22); + theList.removeFront(); + theList.removeFront(); + + assertTrue(theList.isEmpty()); + } + + + + // size() Tests + + + @org.junit.jupiter.api.Test + void sizeWhileEmpty() { + LinkedIntList theList = new LinkedIntList(); + + assertEquals(theList.size(), 0); + } + + @org.junit.jupiter.api.Test + void sizeWithSingleItem() { + LinkedIntList theList = new LinkedIntList(); + + theList.addFront(55); + + assertEquals(theList.size(), 1); + } + + @org.junit.jupiter.api.Test + void sizeWithMultipleItems() { + LinkedIntList theList = new LinkedIntList(); + + for(int i=0; i< 100; i++){ + theList.addBack(i); + } + + assertEquals(theList.size(), 100); + } + + + + // clear() Tests + + + @org.junit.jupiter.api.Test + void clearWithItemsInList() { + LinkedIntList theList = new LinkedIntList(); + + theList.addFront(5); + theList.addFront(50); + theList.addFront(24); + + theList.clear(); + assertEquals(theList.size(), 0); + } + + @org.junit.jupiter.api.Test + void clearWithEmptyList() { + LinkedIntList theList = new LinkedIntList(); + + theList.clear(); + assertEquals(theList.size(), 0); + } + + @org.junit.jupiter.api.Test + void clearAfterAddThenRemoveList() { + LinkedIntList theList = new LinkedIntList(); + + theList.addFront(5); + theList.addFront(50); + theList.removeFront(); + theList.removeFront(); + + theList.clear(); + assertEquals(theList.size(), 0); + } +} \ No newline at end of file diff --git a/src/Main.java b/src/Main.java index 930198c..ba58c91 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,15 +1,117 @@ -//TIP To Run code, press or -// click the icon in the gutter. +import java.util.Iterator; + 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.printf("Hello and welcome!"); - - for (int i = 1; i <= 5; i++) { - //TIP Press to start debugging your code. We have set one breakpoint - // for you, but you can always add more by pressing . - System.out.println("i = " + i); + IntList list1 = new ArrayIntList(); + IntList list2 = new LinkedIntList(); + + System.out.println("------------------ArrayIntList-------------------"); + System.out.println(list1.indexOf(97)); + + // Add 3 ints to the back of the list + list1.addBack(42); + list1.addBack(82); + list1.addBack(97); + list1.addBack(42); + list1.addBack(82); + list1.addBack(97); + + + list1.addFront(99); + + System.out.println(list1); + + list1.add(6, 20); + + System.out.println(list1); + + + System.out.println(list1.indexOf(88)); + + System.out.println(list1); + + + Iterator itr = list1.iterator(); + while (itr.hasNext()){ + int value = itr.next(); + System.out.println(value); + } + + // ----------------------- + // Linked List Short Test + // ----------------------- + + + + System.out.println("------------------LinkedIntList-------------------"); + + System.out.println(list2.contains(22)); + + list2.removeBack(); + System.out.println(list2); + + list2.addFront(42); + System.out.println(list2); + + list2.removeBack(); + System.out.println(list2); + + list2.addFront(82); + list2.addFront(97); + + list2.addBack(50); + list2.addBack(23); + + list2.addFront(30); + + System.out.println(list2); + + for(int value: list2){ + System.out.println(value); } + + list2.removeBack(); + System.out.println(list2); + + list2.removeFront(); + System.out.println(list2); + list2.removeFront(); + System.out.println(list2); + list2.removeFront(); + System.out.println(list2); + list2.removeFront(); + System.out.println(list2); + + list2 = new LinkedIntList(); + + list2.add(0, 10); + System.out.println(list2); + + list2.addFront(2); + list2.addFront(5); + list2.addFront(30); + list2.addFront(92); + System.out.println("94: " + list2); + list2.add(3, 55); + System.out.println("96: " + list2); + list2.add(5, 75); + System.out.println("98: " + list2); + System.out.println(list2.size()-1); + list2.add(list2.size(), 33); + System.out.println("100: " + list2); + + //System.out.println(list2.contains(22)); + //System.out.println(list2.get(0)); + + System.out.println("-------------------"); + System.out.println(list2); + System.out.println(list2.remove(4)); + + System.out.println("-------------------"); + System.out.println(list2); + System.out.println(list2.indexOf(1)); + + //list2.add(1, 20); + //System.out.println(list2); } } \ No newline at end of file