diff --git a/.idea/misc.xml b/.idea/misc.xml index 07115cd..03f397c 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/src/Main.java b/src/Main.java index 3e59c38..51c098b 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,5 +1,325 @@ +import edu.greenriver.sdev333.*; + +import java.util.ListIterator; + +/** + * Did the Level 1, Level 2, and Extras with the exception of the + * hashCode() method. + * + * Main Class used to test functionality of ArrayList implementation. + * Inside the main() method are comments and code regarding the setup + * and testing for each given method. + * + * @author Paul Woods + */ public class Main { + + /* + * private method to print our list, utilizes the Iterator + * via a for-each loop to do so. + */ + private static void printIntList(List l) { + for(int i: l) { + System.out.print(i + " "); + } + System.out.println(); + } + + /** + * Our main method where we have our testing for our List + * classes. + * @param args + */ public static void main(String[] args) { - System.out.println("Hello world!"); + + System.out.println(); + System.out.println("Create list of integers, adding 10 elements, 1 .. 10"); + //List intList = new ArrayList<>(); + List intList = new DoublyLinkedList<>(); + + System.out.println("testing isEmpty on empty list, returns: " + intList.isEmpty()); + + // tests .add() + intList.add(1); + intList.add(2); + intList.add(3); + intList.add(4); + intList.add(5); + intList.add(6); + intList.add(7); + intList.add(8); + intList.add(9); + intList.add(10); + printIntList(intList); +/* + System.out.println("removing index 5 (#6)"); + intList.remove(5); + printIntList(intList); + + System.out.println("removing index 0 (#1)"); + intList.remove(0); // remove index + printIntList(intList); + + System.out.println("removing item 2"); + intList.remove(Integer.valueOf(2)); // remove item - problem w/ iterator after this point + printIntList(intList); + + System.out.println("removing item 7"); + intList.remove(Integer.valueOf(7)); + printIntList(intList); + + System.out.println("Clearing list, then adding numbers 21..25"); + intList.clear(); + + intList.add(21); + intList.add(22); + intList.add(23); + intList.add(24); + intList.add(25); + printIntList(intList); + + // BEGIN TEST ITERATOR + System.out.println("Testing ListIterator forward"); + ListIterator myItr = intList.listIterator(); + while(myItr.hasNext()) { + System.out.print(myItr.next() + " "); + } + System.out.println(); + + System.out.println("Testing in reverse"); + while(myItr.hasPrevious()) { + System.out.print(myItr.previous() + " "); + } + System.out.println(); + // END TEST ITERATOR + */ + + // NEW FOR DOUBLYLINKEDARRAYLIST +// System.out.println("Printing List organically w/o iterator"); +// for (int i = 0; i < intList.size(); i++) { +// System.out.print(intList.get(i) + " "); +// } +// System.out.println(); + // END NEW TEST + + System.out.println("testing isEmpty on a list with 10 items, returns: " + intList.isEmpty()); + System.out.println(); + System.out.println("Testing get(0):, should return 1: " + intList.get(0)); + System.out.println(); + System.out.println("testing contains(), looking for int value 5"); + System.out.println("result of contains(Integer.valueOf(5)): " + intList.contains(Integer.valueOf(5))); + System.out.println("testing contains(), looking for int value of 90"); + System.out.println("result of contains(Integer.valueOf(90)): " + intList.contains(Integer.valueOf(90))); + System.out.println(); + + System.out.println("Printing list while testing .iterator() ..."); + // tests .iterator() + printIntList(intList); + System.out.println(); + + // test .add() again + System.out.println("Adding 20 to list"); + intList.add(20); + System.out.println("Size: " + intList.size()); + printIntList(intList); + System.out.println(); + + // test .set(index, value) + System.out.println("Setting index 8 (#9) to 90"); + intList.set(8, 90); + System.out.println("Size: " + intList.size()); + printIntList(intList); + System.out.println(); + + // test .add(index, value) + System.out.println("Adding 40 at index 4"); + intList.add(4,40); + System.out.println("Size: " + intList.size()); + printIntList(intList); + System.out.println(); + + // test .indexOf(val) + System.out.println("Testing indexOf(item), index of 90 should be 9."); + System.out.println(intList.indexOf(90)); + System.out.println(); + + // test .indexOf(val) + System.out.println("Testing indexOf(item), index of 3 should be 2."); + System.out.println(intList.indexOf(3)); + System.out.println(); + + // add 5 again, and reprint list + System.out.println("Adding 5 to end of list for next test"); + intList.add(5); + printIntList(intList); + System.out.println(); + + // test .lastIndexOf(val) + System.out.println("Finding last index of 5, should be 12"); + System.out.println("Calculated lastIndex of 5: " + intList.lastIndexOf(5)); + System.out.println("Finding last index of 40, should be 4"); + System.out.println("Calculated lastIndex of 40: " + intList.lastIndexOf(40)); + System.out.println(); + + printIntList(intList); + + // testing remove(index) + System.out.println("Testing remove(index), removing index 4 (#40)"); + intList.remove(4); + printIntList(intList); + System.out.println(); + + // test containsAll() + List newList = new DoublyLinkedList<>(); + newList.add(1); + newList.add(8); + System.out.println("Testing containsAll() with a sublist of 1 and 8, should return true"); + System.out.println("containsAll() result: " + intList.containsAll(newList)); + newList.add(999); + System.out.println("Testing containsAll() with a sublist of 1, 8, and 999 should return false"); + System.out.println("containsAll() result: " + intList.containsAll(newList)); + printIntList(intList); + System.out.println(); + + // tests removeItem(item) + System.out.println("Testing remove(item), removing #90"); + intList.remove(Integer.valueOf(90)); + // NOTE - Use the Integer.valueOf() static method to remove a value as from ArrayList + + printIntList(intList); + System.out.println(); + + // test clear() + System.out.println(); + System.out.println("Testing clear(), printed list"); + intList.clear(); + printIntList(intList); + System.out.println(); + + // testing 2nd constructor w/ initial parameter + intList = new DoublyLinkedList<>(); + intList.add(1); + intList.add(2); + intList.add(3); + intList.add(4); + intList.add(5); + intList.add(6); + intList.add(7); + intList.add(8); + intList.add(9); + intList.add(10); + System.out.println("Testing 2nd constructor w/ initial size parameter, should have 1..10 entered."); + System.out.println("Note, no 2nd constructor for DoublyLinkedList, using original ... "); + printIntList(intList); + System.out.println(); + + // testing addAll(collection) + List tempList = new DoublyLinkedList<>(); + tempList.add(50); + tempList.add(51); + tempList.add(52); + tempList.add(53); + tempList.add(54); + tempList.add(55); + System.out.println("Testing addAll(), adding a new collection that contains 50 ... 55 to list"); + intList.addAll(tempList); + printIntList(intList); + System.out.println(); + + // testing equals() method + System.out.println("Testing equals() method, original list vs tempList (50..55), should be false"); + System.out.println("Result of intList.equals(tempList): " + intList.equals(tempList)); + System.out.println("Testing equals method, tempList (50..55) vs bList (50..55), should be true"); + List bList = new DoublyLinkedList<>(); + bList.add(50); + bList.add(51); + bList.add(52); + bList.add(53); + bList.add(54); + bList.add(55); + System.out.println("Result of tempList.equals(bList): " + tempList.equals(bList)); + + System.out.println(); + System.out.println("Original list again:"); + printIntList(intList); + + + // BEGIN TEST ITERATOR + System.out.println("Testing ListIterator forward"); + ListIterator myItr = intList.listIterator(); + while(myItr.hasNext()) { + System.out.print(myItr.next() + " "); + } + System.out.println(); + + System.out.println("Testing in reverse"); + while(myItr.hasPrevious()) { + System.out.print(myItr.previous() + " "); + } + System.out.println(); + // END TEST ITERATOR + + + + System.out.println(); + + List cList = new DoublyLinkedList<>(); + cList.add(1); + cList.add(5); + cList.add(9); + cList.add(52); + cList.add(55); + cList.add(72); + + // testing removeAll(collection) + System.out.println("Will be removing cList from our original list, cList is:"); + printIntList(cList); + System.out.println("Testing removeAll(collection), removing cList from intList."); + intList.removeAll(cList); + System.out.println("Resulting list: "); + printIntList(intList); + System.out.println(); + + // testing retainAll() + System.out.println("We are going to test retainAll(), but lets add items back to our original list."); + System.out.println("Original list again:"); + intList.addAll(cList); + + cList.add(99); + printIntList(intList); + System.out.println("cList again is (added 99 to this list):"); + printIntList(cList); + System.out.println("We are going to retain only the items in cList that are in our original list"); + intList.retainAll(cList); + System.out.println("Resulting original list:"); + printIntList(intList); + + System.out.println("Adding 1..10 to original list again"); + intList.add(1); + intList.add(2); + intList.add(3); + intList.add(4); + intList.add(5); + intList.add(6); + intList.add(7); + intList.add(8); + intList.add(9); + intList.add(10); + printIntList(intList); + + System.out.println("Testing ListIterator forward"); + //ListIterator myItr = intList.listIterator(); + myItr = intList.listIterator(); + while(myItr.hasNext()) { + System.out.print(myItr.next() + " "); + } + System.out.println(); + + System.out.println("Testing in reverse"); + while(myItr.hasPrevious()) { + System.out.print(myItr.previous() + " "); + } + System.out.println(); + } } \ No newline at end of file diff --git a/src/edu/greenriver/sdev333/ArrayList.java b/src/edu/greenriver/sdev333/ArrayList.java new file mode 100644 index 0000000..d31c5cb --- /dev/null +++ b/src/edu/greenriver/sdev333/ArrayList.java @@ -0,0 +1,529 @@ +package edu.greenriver.sdev333; + +import java.util.Iterator; +import java.util.ListIterator; + +/** + * This class implements the List interface in the Java collections + * package. The individual public methods are tested in the + * corresponding Main class, with comments there regarding each + * method tested. + * + * Implemented and tested all listed methods except for hashCode(). I read in + * prior class notes from CS145 "If the .equals() method returns true on two objects, + * their hashCode() must also return the same value." I am unsure how I can + * get two 'equal' lists to return the same hashCode if they have equal objects, + * so am going to forgo that method for now. + * + * @author Paul Woods + * + * @param + */ +public class ArrayList implements List { + + // WE NEED FIELDS + + // one plain Java array + private ItemType[] data; + + // one int to keep track of size + // size is the number of spots used in the data array + // size is different than length + private int size; + + public ArrayList() { + size = 0; + data = (ItemType[]) new Object[10]; + } + + public ArrayList(int initial) { + size = 0; + data = (ItemType[]) new Object[initial]; + } + + + /** + * Returns the number of items in this collection. + * + * @return the number of items in this collection + */ + @Override + public int size() { + return size; + } + + /** + * Returns true if this collection contains no items. + * + * @return true if this collection contains no items + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns true if this collection contains the specified item. + * + * @param item items whose presence in this collection is to be tested + * @return true if this collection contains the specified item + * @throws NullPointerException if the specified item is null + * and this collection does not permit null items + */ + @Override + public boolean contains(ItemType item) { + if (item == null) { + throw new NullPointerException(); + } + + return (indexOf(item) != -1); + } + + /** + * Returns an iterator over the elements in this collection. + * + * @return an Iterator over the elements in this collection + */ + @Override + public Iterator iterator() { + return new OurCustomIterator(); + } + + /** + * Adds the specified item to the collection. + * + * @param item item to be added to the collection + * @throws NullPointerException if the specified item is null + * and this collection does not permit null items + */ + @Override + public void add(ItemType item) { + data[size++] = item; + + // all of the above works until I run out of room when size becomes + // the same as length, I'm out of room + checkSize(); + + } + + /* + * check for size increase requirement, and double-array size + * if necessary + */ + private void checkSize() { + if (size == data.length) { + // resize up .... + + // Step 1 - create a temp array 2x size + ItemType[] temp = (ItemType[]) new Object[data.length * 2];; + + // Step 2 - copy arrayElements from data to temp + for (int i = 0; i < size; i++) { + temp[i] = data[i]; + } + + // Step 3 - point 'data' at temp array + data = temp; + } + } + + /** + * Removes a single instance of the specified item from this collection, + * if it is present. + * + * @param item item to be removed from this collection, if present + * @throws NullPointerException if the specified item is null + * and this collection does not permit null items + */ + @Override + public void remove(ItemType item) { + if (item == null) { + throw new NullPointerException(); + } + // IN CLASS + int i = indexOf(item); + if (i != -1) { + remove(i); + } + } + + /** + * Removes all items from this collection. + * The collection will be empty after this method returns. + */ + @Override + public void clear() { + // data = (ItemType[]) new Object[data.length]; + size = 0; + } + + /** + * Returns true if this collection contains all the items + * in the specified other collection. + * + * @param otherCollection collection to be checked for containment in this collection + * @return true if this collection contains all the items + * in the specified other collection + */ + @Override + public boolean containsAll(Collection otherCollection) { + + for (ItemType i: otherCollection) { + if (!contains(i)) + return false; + } + + return true; + } + + /** + * Adds all the items in this specified other collection to this collection. + * + * @param otherCollection collection containing items to be added to this collection + */ + @Override + public void addAll(Collection otherCollection) { + if (otherCollection != null) { + for (ItemType i: otherCollection) { + this.add(i); + } + } + } + + /** + * Removes all of this collection's items that are also contained in the + * specified other collection. After this call returns, this collection will + * contain no elements in common with the specified other collection. + * + * @param otherCollection collection containing elements to be removed + * from this collection + */ + @Override + public void removeAll(Collection otherCollection) { + for (ItemType i: otherCollection) { + remove(i); + } + } + + /** + * Retains only the items in this collection that are contained in the + * specified other collection. In other words, removes from this collection + * all of its items that are not contained in the specified other collection + * + * @param otherCollection collection containing elements to be retained in + * this collection + */ + @Override + public void retainAll(Collection otherCollection) { + // Create a value-copy of current list + List listCopy = new ArrayList<>(); + for (ItemType i: this) { + listCopy.add(i); + } + + // remove items in otherCollection from listCopy + // this leaves us with an inverted view of the list + listCopy.removeAll(otherCollection); + + // now remove listCopy items from originalList + this.removeAll(listCopy); + } + + /** + * Returns the item at the specified position in this list + * + * @param index index of the item to return + * @return the item at the specified position in this list + * @throws IndexOutOfBoundsException if this index is out of range + * (index < 0 || index >= size()) + */ + @Override + public ItemType get(int index) { + if (validIndex(index)) { + return data[index]; + } + else { + throw new IndexOutOfBoundsException("index is beyond size"); + } + } + + /** + * Replaces the item at the specified position in this list + * with the specified item + * + * @param index index of the item to replace + * @param item item to be stored at the specified position + * @throws NullPointerException if the specified item is null + * and this list does not permit null elements + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + @Override + public void set(int index, ItemType item) { + if (validIndex(index)) { + data[index] = item; + } else { + throw new IndexOutOfBoundsException("index is beyond size"); + } + } + + /** + * Inserts the specified item at the specified position in this list. + * Shifts the item currently at that position (if any) and any subsequent + * items to the right. + * + * @param index index at which the specified item is to be inserted + * @param item item to be inserted + * @throws NullPointerException if the specified item is null + * and this list does not permit null elements + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + @Override + public void add(int index, ItemType item) { + if (validIndex(index)) { + // Add the last item to the end of list, and shift everything behind it to the right + this.add(data[size-1]); + + for (int i = size-2; i > index; i--) { + data[i] = data[i-1]; + } + + // finally, set the 'added' item to the specified location + set(index, item); + } + } + + /** + * Removes the element at the specified position in this list. + * Shifts any subsequent items to the left. + * + * @param index the index of the item to be removed + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + @Override + public void remove(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(); + } + + for (int i = index; i < size - 1; i++) { + data[i] = data[i + 1]; + } + + size--; + } + + /** + * Returns the index of the first occurrence of the specified item + * in this list, or -1 if this list does not contain the item. + * + * @param item the item to search for + * @return the index of the first occurrence of the specified item + * in this list, or -1 if this list does not contain the item + * @throws NullPointerException if the specified item is null and this + * list does not permit null items + */ + @Override + public int indexOf(ItemType item) { + // DID AT HOME + for (int i = 0; i < size; i++) { + if (data[i].equals(item)) + return i; + } + + return -1; + } + + /** + * Returns the index of the last occurrence of the specified item + * in this list, or -1 if this list does not contain the item. + * + * @param item the item to search for + * @return the index of the first occurrence of the specified item + * in this list, or -1 if this list does not contain the item + * @throws NullPointerException if the specified item is null and this + * list does not permit null items + */ + @Override + public int lastIndexOf(ItemType item) { + for (int i = size-1; i >= 0; i--) { + if (data[i].equals(item)) + return i; + } + + return -1; + } + + /** + * Returns a list iterator over the elements in this list + * (in proper sequence). + * + * @return a list iterator over the elements in this list + * (in proper sequence) + */ + @Override + public ListIterator listIterator() { + return new SecondCustomIterator(); + } + + /** + * Per the Oracle javadocs, "... two lists are defined to be equal + * if they contain the same elements in the same order." + * @param obj object to be compared for equality with this collection + * @return + */ + @Override + public boolean equals(Object obj) { + // Must first ensure these two objects are of the same type ... + if (obj != null && obj.getClass() == this.getClass()) { + + // create temporary ArrayList from obj + ArrayList temp = (ArrayList) obj; + + // confirm lists are of equal size, if not, return false + if (this.size() != temp.size()) + return false; + + // cycle through individual items, testing one by one + // return false if one of pair is not equal + for (int i = 0; i < this.size(); i++) { + if (this.get(i) != temp.get(i)) + return false; + } + } + + return true; + } + + /** + * This method tests a given index value to determine if it + * is valid. Any index out of range, i.e. smaller than 0 + * or larger than size, is invalid and does not point to + * a valid element. + * @param index + * @return + */ + private boolean validIndex(int index) { + return ((index < this.size) && (index >= 0)); + } + + /** + * This method resizes the array, doubling its previous value, to + * make way for new elements. Called as required by various methods. + */ + private void resize() { + // Step 1 - create a temp array 2x size + ItemType[] temp = (ItemType[]) new Object[data.length * 2];; + + // Step 2 - copy arrayElements from data to temp + for (int i = 0; i < size; i++) { + temp[i] = data[i]; + } + + // Step 3 - point 'data' at temp array + data = temp; + } + + private class OurCustomIterator implements Iterator { + + // fields + private int currentPosition; + + public OurCustomIterator() { + currentPosition = 0; + } + + @Override + public boolean hasNext() { + return currentPosition < size(); + } + + @Override + public ItemType next() { + ItemType result = get(currentPosition); + currentPosition++; + return result; + } + + } + + /** + * Implemented methods using primarily same logic as CustomerIterator + * above, though the extra methods were completed using documentation found + * for the JDK at + * https://docs.oracle.com/javase/8/docs/api/java/util/ListIterator.html#previousIndex-- + */ + private class SecondCustomIterator implements ListIterator { + + // fancier Iterator that lets us go forwards and backwards + private int currentPosition; + private int lastIndexReturned; + + public SecondCustomIterator() { + currentPosition = 0; + } + + @Override + public boolean hasNext() { + return currentPosition < size(); + } + + @Override + public ItemType next() { + ItemType result = get(currentPosition); + lastIndexReturned = currentPosition; + currentPosition++; + return result; + } + + @Override + public boolean hasPrevious() { + return currentPosition > 0; + } + + @Override + public ItemType previous() { + if (currentPosition > 0) { + ItemType result = get(currentPosition - 1); + lastIndexReturned = currentPosition - 1; + return result; + } else { + throw new IndexOutOfBoundsException(); + } + } + + @Override + public int nextIndex() { + if (currentPosition == size() - 1) + return currentPosition; + else + return currentPosition + 1; + } + + @Override + public int previousIndex() { + if (currentPosition == 0) + return -1; + else + return currentPosition - 1; + } + + @Override + public void remove() { + ArrayList.this.remove(lastIndexReturned); + } + + @Override + public void set(ItemType itemType) { + ArrayList.this.set(lastIndexReturned, itemType); + } + + @Override + public void add(ItemType itemType) { + + } + } + +} // end of class ArrayList diff --git a/src/edu/greenriver/sdev333/DoublyLinkedList.java b/src/edu/greenriver/sdev333/DoublyLinkedList.java new file mode 100644 index 0000000..21c58ae --- /dev/null +++ b/src/edu/greenriver/sdev333/DoublyLinkedList.java @@ -0,0 +1,613 @@ +package edu.greenriver.sdev333; + +import java.util.Iterator; +import java.util.ListIterator; + +/** + * Did the Level 1, Level 2, and Extras with the exception of the + * hashCode() method. + * + * This class implements the List interface. Testing is done in the + * Main class, and there were intial bugs found and then corrected, + * esp wrt to the ListIterator class. I had to cycle through the + * Main tests comment them out to determine what was interfering + * with my list of Nodes (was remove(item)). + * + * @author Paul Woods + */ +public class DoublyLinkedList implements List{ + + private Node head; + private int size; + + // helper/inner class + private class Node { + ItemType data; + Node next; + Node previous; + } + + /* + * Test w/ for-each statemenet + */ + private class OurCustomIterator implements Iterator { + + private Node iHead; + + public OurCustomIterator() { + //iHead = DoublyLinkedList.this.head; + iHead = head; + } + @Override + public boolean hasNext() { + // Ken tested for if (currentPostition != null) ... but he had reversed the two lines in next() as well + //return iHead.next != null; + if ((iHead != null) && iHead.next != null) + return true; + return false; + } + + /* + * Ken had iHead.next and result = lines reversed + */ + @Override + public ItemType next() { + iHead = iHead.next; + ItemType result = (ItemType) iHead.data; + return result; + } + } + + // geeksforgeeks.org/difference-between-an-iterator-and-listiterator-in-java/ + private class OurListIterator implements ListIterator { + + private Node iHead; + private Node priorNode; + + public OurListIterator() { + iHead = head; + } + @Override + public boolean hasNext() { + return iHead.next != null; + } + + @Override + public ItemType next() { + iHead = iHead.next; + ItemType result = (ItemType) iHead.data; + priorNode = iHead; + return result; + } + + @Override + public boolean hasPrevious() { + //return iHead.previous != null; + //return iHead.previous != null; + return iHead != null; + } + + @Override + public ItemType previous() { + //iHead = iHead.previous; + //ItemType result = (ItemType) iHead.data; + ItemType result = (ItemType) iHead.data; + //if (iHead.previous != null) + iHead = iHead.previous; + priorNode = iHead; + return result; + } + + @Override + public int nextIndex() { + if (iHead.next == null) + return size(); + + ItemType next = next(); + Node node = head; + int i = 0; + + while (node.next != null) { + node = node.next; + i++; + if (node.next.data.equals(next)) { + return i; + } + } + + return 0; + } + + @Override + public int previousIndex() { + if (iHead.previous == null) + return -1; + + ItemType prev = (ItemType) iHead.previous.data; + Node node = head; + int i = -1; + + while (node.next != null) { + node = node.next; // will be head node w/ index 0 to start + i++; + if (node.data.equals(prev)) { + return i; + } + } + + return -1; + } + + @Override + public void remove() { + // both prior and next nodes ARE NOT null + if (priorNode.previous != null && priorNode.next != null) { + priorNode.previous.next = priorNode.next; // prior nodes' next value = next node + priorNode.next.previous = priorNode.previous; + } + // both prior and next nodes ARE null (single item in list) + else if (priorNode.previous == null && priorNode.next == null) { + iHead.next = null; + } + // prior only IS NULL (1st item in list) + else if (priorNode.previous == null) { + iHead = priorNode.next; + } + // next only IS NULL (last item in list) + else if (priorNode.next == null) { + priorNode.next = null; + } + } + + @Override + public void set(ItemType itemType) { + + } + + @Override + public void add(ItemType itemType) { + + } + } + + /* + * Return a pointer to the last element in the linked-list + */ + private Node getLastElement() { + if (size == 0) { + return null; + } else { + Node n = head; + while (n.next != null) { + n = n.next; + } + return n; + } + } + + /* + * could have been left inside getElementN, but broken into a separate method for use + * by other methods if required + */ + private void validateIndex(int index) { + if ((index >= size) || (index < 0)) + throw new IndexOutOfBoundsException(); + } + + /* + * Return element at index n (not the data in that element) + */ + private Node getElementN(int index) { + + validateIndex(index); + + Node n = head; + int i = -1; + + while (n.next != null) { + i++; + n = n.next; + if (i == index) { + //System.out.println("data, " + n.data); + return n; + } + } + + // we shouldn't be here ... + throw new NullPointerException(); + } + + public DoublyLinkedList() { + // A new list contains no elemenets, so its head is null + head = null; + size = 0; + } + + /** + * Returns the number of items in this collection. + * + * @return the number of items in this collection + */ + @Override + public int size() { + return size; + } + + /** + * Returns true if this collection contains no items. + * + * @return true if this collection contains no items + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns true if this collection contains the specified item. + * + * @param item items whose presence in this collection is to be tested + * @return true if this collection contains the specified item + * @throws NullPointerException if the specified item is null + * and this collection does not permit null items + */ + @Override + public boolean contains(ItemType item) { + + if (size == 0) + return false; + + return indexOf(item) != -1; + } + + /** + * Returns an iterator over the elements in this collection. + * + * @return an Iterator over the elements in this collection + */ + @Override + public Iterator iterator() { + return new OurCustomIterator<>(); + } + + /** + * Adds the specified item to the collection. + * + * @param item item to be added to the collection + * @throws NullPointerException if the specified item is null + * and this collection does not permit null items + */ + @Override + public void add(ItemType item) { + + if (head == null) { // Add new 1st item, item.previous = null + head = new Node(); + head.next = new Node(); + head.next.data = item; + } else { + Node currentLast = getLastElement(); + + currentLast.next = new Node(); + currentLast.next.data = item; + currentLast.next.previous = currentLast; + } + + ++size; + } + + /** + * Compares the specified object (a collection) with this collection for equality. + * + * Equal only if the lists are the same size, and each node equals the matching + * node in the alternate list. + * + * @param obj object to be compared for equality with this collection + * @return true if the specified other object is equal to this collection + */ + @Override + public boolean equals(Object obj) { + // https://docs.oracle.com/javase/7/docs/api/java/util/AbstractList.html#equals(java.lang.Object) + // object is not null, and it matches this class type + if (obj != null && obj.getClass() == this.getClass()) { + + List list = (List) obj; + + if (this.size != list.size()) + return false; + + ListIterator litA = this.listIterator(); + ListIterator litB = list.listIterator(); + while (litA.hasNext()) { + if (!litA.next().equals(litB.next())) + return false; + } + } else { + return false; + } + + return true; + } + + /** + * Removes a single instance of the specified item from this collection, + * if it is present. + * + * @param item item to be removed from this collection, if present + * @throws NullPointerException if the specified item is null + * and this collection does not permit null items + */ + @Override + public void remove(ItemType item) { + if (item == null) + throw new NullPointerException(); + + Node n = head; + + // 1st Node is treated differently as it has no valid previous + if (n.next.data.equals(item)) { + n.next = n.next.next; + n.next.previous = null; + --size; + } + else { + while (n.next != null) { + n = n.next; + if (n.data.equals(item)) { + if (n.next != null) + n.next.previous = n.previous; // assign 'previous' for following node to prior node + n.previous.next = n.next; // assign 'next' for prior node to n.next + --size; + return; + } + } + } + + } + + /** + * Removes all items from this collection. + * The collection will be empty after this method returns. + */ + @Override + public void clear() { + head = null; + size = 0; + } + + /** + * Returns true if this collection contains all the items + * in the specified other collection. + * + * @param otherCollection collection to be checked for containment in this collection + * @return true if this collection contains all the items + * in the specified other collection + */ + @Override + public boolean containsAll(Collection otherCollection) { + // Cycle through otherCollection, and when find an element from that + // collection here, remove it. If at some point we do not find one of those + // elements, return false. If we make it through the list, return true + for (ItemType i: otherCollection) { + if (!this.contains(i)) + return false; + } + + return true; + } + + /** + * Adds all the items in this specified other collection to this collection. + * + * @param otherCollection collection containing items to be added to this collection + */ + @Override + public void addAll(Collection otherCollection) { + if (otherCollection != null) { + for (ItemType i: otherCollection) { + this.add(i); + } + } + } + + /** + * Removes all of this collection's items that are also contained in the + * specified other collection. After this call returns, this collection will + * contain no elements in common with the specified other collection. + * + * @param otherCollection collection containing elements to be removed + * from this collection + */ + @Override + public void removeAll(Collection otherCollection) { + if (otherCollection != null) { + for (ItemType i: otherCollection) { + this.remove(i); + } + } + } + + /** + * Retains only the items in this collection that are contained in the + * specified other collection. In other words, removes from this collection + * all of its items that are not contained in the specified other collection + * + * @param otherCollection collection containing elements to be retained in + * this collection + */ + @Override + public void retainAll(Collection otherCollection) { + // Create a value-copy of current list + List listCopy = new ArrayList<>(); + for (ItemType i: this) { + listCopy.add(i); + } + + // remove items in otherCollection from listCopy + // this leaves us with an inverted view of the list + listCopy.removeAll(otherCollection); + + // now remove listCopy items from originalList + this.removeAll(listCopy); + } + + /** + * Returns the item at the specified position in this list + * + * @param index index of the item to return + * @return the item at the specified position in this list + * @throws IndexOutOfBoundsException if this index is out of range + * (index < 0 || index >= size()) + */ + @Override + public ItemType get(int index) { + return getElementN(index).data; + } + + /** + * Replaces the item at the specified position in this list + * with the specified item + * + * @param index index of the item to replace + * @param item item to be stored at the specified position + * @throws NullPointerException if the specified item is null + * and this list does not permit null elements + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + @Override + public void set(int index, ItemType item) { + if (item == null) + throw new NullPointerException(); + + Node i = getElementN(index); + i.data = item; + } + + /** + * Inserts the specified item at the specified position in this list. + * Shifts the item currently at that position (if any) and any subsequent + * items to the right. + * + * @param index index at which the specified item is to be inserted + * @param item item to be inserted + * @throws NullPointerException if the specified item is null + * and this list does not permit null elements + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + @Override + public void add(int index, ItemType item) { + if (item == null) + throw new NullPointerException(); + + Node i = getElementN(index); // current element at index + Node n = new Node(); // new node to be inserted + n.data = item; + if (index != 0) + n.previous = i.previous; // previous value for new node + n.next = i; // next value for new node + i.previous.next = n; // next value for old prior node + i.previous = n; // previous value for old node + + ++size; + } + + /** + * Removes the element at the specified position in this list. + * Shifts any subsequent items to the left. + * + * @param index the index of the item to be removed + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + @Override + public void remove(int index) { + Node i = getElementN(index); + + if (index == 0) { + head.next = i.next; + i.next.previous = null; + } else { + i.previous.next = i.next; + i.next.previous = i.previous; + } + + --size; + } + + /** + * Returns the index of the first occurrence of the specified item + * in this list, or -1 if this list does not contain the item. + * + * @param item the item to search for + * @return the index of the first occurrence of the specified item + * in this list, or -1 if this list does not contain the item + * @throws NullPointerException if the specified item is null and this + * list does not permit null items + */ + @Override + public int indexOf(ItemType item) { + if (item == null) + throw new NullPointerException(); + + Node n = head; + int i = -1; + + while (n.next != null) { + i++; + n = n.next; + if (n.data.equals(item)) + return i; + } + + return -1; + } + + /** + * Returns the index of the last occurrence of the specified item + * in this list, or -1 if this list does not contain the item. + * + * @param item the item to search for + * @return the index of the first occurrence of the specified item + * in this list, or -1 if this list does not contain the item + * @throws NullPointerException if the specified item is null and this + * list does not permit null items + */ + @Override + public int lastIndexOf(ItemType item) { + + if (item == null) + throw new NullPointerException(); + + Node n = getLastElement(); + int index = size - 1; + + while (true) { + + if (n.data.equals(item)) + return index; + + if (n.previous != null) { + n = n.previous; + //System.out.println("cycling through last-index, looking for " + item + ", have " + n.data); + --index; + } else { + break; + } + } + + return -1; + } + + /** + * Returns a list iterator over the elements in this list + * (in proper sequence). + * + * @return a list iterator over the elements in this list + * (in proper sequence) + */ + @Override + public ListIterator listIterator() { + return new OurListIterator<>(); + } +} diff --git a/src/edu/greenriver/sdev333/SinglyLinkedList.java b/src/edu/greenriver/sdev333/SinglyLinkedList.java new file mode 100644 index 0000000..c84d31a --- /dev/null +++ b/src/edu/greenriver/sdev333/SinglyLinkedList.java @@ -0,0 +1,332 @@ +package edu.greenriver.sdev333; + +import java.util.Iterator; +import java.util.ListIterator; + +/** + * NOT TESTED - SEE DoublyLinkedList + * This class implements the List interface using a SinglyLinkedList. + * The code here is not complete, I finished implementing this + * interface using a DoublyLinkedList instead. + * + * @author Paul Woods + * @param + */ + +public class SinglyLinkedList implements List { + + // FIELDS - what does a linked list actually have in it?? + private Node head; + private Node tail; + private int size; + + // helper/inner class + private class Node { + ItemType data; + Node next; + } + + /** + * Constructor + */ + public SinglyLinkedList() { + // an empty list has no nodes, + // which means it has no head + head = null; + size = 0; + } + + + + /* + * Return a pointer to the last element in the linked-list + */ + private SinglyLinkedList.Node getLastElement() { + if (size == 0) { + return null; + } else { + SinglyLinkedList.Node n = head; + while (n.next != null) { + n = n.next; + } + return n; + } + } + + + /* + * Return element at index n + */ + private SinglyLinkedList.Node getElementN(int index) { + + //System.out.print("Retrieving element " + index + ", "); + + if ((index >= size) || (index < 0)) + throw new IndexOutOfBoundsException(); + + SinglyLinkedList.Node n = head; + int i = -1; + + while (n.next != null) { + i++; + n = n.next; + if (i == index) { + //System.out.println("data, " + n.data); + return n; + } + } + + // we shouldn't be here ... + throw new NullPointerException(); + } + + /** + * Returns the number of items in this collection. + * + * @return the number of items in this collection + */ + @Override + public int size() { + return size; + } + + /** + * Returns true if this collection contains no items. + * + * @return true if this collection contains no items + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns true if this collection contains the specified item. + * + * @param item items whose presence in this collection is to be tested + * @return true if this collection contains the specified item + * @throws NullPointerException if the specified item is null + * and this collection does not permit null items + */ + @Override + public boolean contains(ItemType item) { + return false; + } + + /** + * Returns an iterator over the elements in this collection. + * + * @return an Iterator over the elements in this collection + */ + @Override + public Iterator iterator() { + return null; + } + + /** + * Adds the specified item to the collection. + * + * @param item item to be added to the collection + * @throws NullPointerException if the specified item is null + * and this collection does not permit null items + */ + @Override + public void add(ItemType item) { + + if (head == null) { + head = new SinglyLinkedList.Node(); + head.next = new SinglyLinkedList.Node(); + head.next.data = item; + } else { + SinglyLinkedList.Node currentLast = getLastElement(); + + currentLast.next = new SinglyLinkedList.Node(); + currentLast.next.data = item; + } + + ++size; + } + + /** + * Removes a single instance of the specified item from this collection, + * if it is present. + * + * @param item item to be removed from this collection, if present + * @throws NullPointerException if the specified item is null + * and this collection does not permit null items + */ + @Override + public void remove(ItemType item) { + + } + + /** + * Removes all items from this collection. + * The collection will be empty after this method returns. + */ + @Override + public void clear() { + head = null; + size = 0; + } + + /** + * Returns true if this collection contains all the items + * in the specified other collection. + * + * @param otherCollection collection to be checked for containment in this collection + * @return true if this collection contains all the items + * in the specified other collection + */ + @Override + public boolean containsAll(Collection otherCollection) { + return false; + } + + /** + * Adds all the items in this specified other collection to this collection. + * + * @param otherCollection collection containing items to be added to this collection + */ + @Override + public void addAll(Collection otherCollection) { + + } + + /** + * Removes all of this collection's items that are also contained in the + * specified other collection. After this call returns, this collection will + * contain no elements in common with the specified other collection. + * + * @param otherCollection collection containing elements to be removed + * from this collection + */ + @Override + public void removeAll(Collection otherCollection) { + + } + + /** + * Retains only the items in this collection that are contained in the + * specified other collection. In other words, removes from this collection + * all of its items that are not contained in the specified other collection + * + * @param otherCollection collection containing elements to be retained in + * this collection + */ + @Override + public void retainAll(Collection otherCollection) { + + } + + /** + * Returns the item at the specified position in this list + * + * @param index index of the item to return + * @return the item at the specified position in this list + * @throws IndexOutOfBoundsException if this index is out of range + * (index < 0 || index >= size()) + */ + @Override + public ItemType get(int index) { + return null; + } + + /** + * Replaces the item at the specified position in this list + * with the specified item + * + * @param index index of the item to replace + * @param item item to be stored at the specified position + * @throws NullPointerException if the specified item is null + * and this list does not permit null elements + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + @Override + public void set(int index, ItemType item) { + + } + + /** + * Inserts the specified item at the specified position in this list. + * Shifts the item currently at that position (if any) and any subsequent + * items to the right. + * + * @param index index at which the specified item is to be inserted + * @param item item to be inserted + * @throws NullPointerException if the specified item is null + * and this list does not permit null elements + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + @Override + public void add(int index, ItemType item) { + if (item == null) + throw new NullPointerException(); +// +// DoublyLinkedList.Node i = getElementN(index); +// DoublyLinkedList.Node n = new DoublyLinkedList.Node(); +// n.data = item; +// n.previous = i.previous; // previous value for new node +// n.next = i; // next value for new node +// i.previous.next = n; // next value for old prior node +// i.previous = n; // previous value for old node +// ++size; + } + + /** + * Removes the element at the specified position in this list. + * Shifts any subsequent items to the left. + * + * @param index the index of the item to be removed + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + @Override + public void remove(int index) { + + } + + /** + * Returns the index of the first occurrence of the specified item + * in this list, or -1 if this list does not contain the item. + * + * @param item the item to search for + * @return the index of the first occurrence of the specified item + * in this list, or -1 if this list does not contain the item + * @throws NullPointerException if the specified item is null and this + * list does not permit null items + */ + @Override + public int indexOf(ItemType item) { + return 0; + } + + /** + * Returns the index of the last occurrence of the specified item + * in this list, or -1 if this list does not contain the item. + * + * @param item the item to search for + * @return the index of the first occurrence of the specified item + * in this list, or -1 if this list does not contain the item + * @throws NullPointerException if the specified item is null and this + * list does not permit null items + */ + @Override + public int lastIndexOf(ItemType item) { + return 0; + } + + /** + * Returns a list iterator over the elements in this list + * (in proper sequence). + * + * @return a list iterator over the elements in this list + * (in proper sequence) + */ + @Override + public ListIterator listIterator() { + return null; + } +}