diff --git a/src/Main.java b/src/Main.java index 511bbf9..a2615ed 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,60 +1,246 @@ import edu.greenriver.sdev333.*; -import java.util.Iterator; + import java.util.ListIterator; +/** + * main class that runs everything + * + * @author Jack Ruiz + */ public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); - - List friends = new SinglyLinkedList(); - - System.out.println("initial size is " + friends.size()); - - friends.add("Jess"); - friends.add("Tina"); - friends.add("Josh"); - friends.add("Susan"); - friends.add("Tyler"); - friends.add("Usman"); - friends.add("Dee"); - friends.add("Rose"); - friends.add("Blanche"); - friends.add("Dorothy"); - friends.add("Sophia"); - friends.add(2, "Wednesday"); - System.out.println("size is now " + friends.size()); - - //for (int i = 0; i < friends.size(); i++) { - // System.out.println(friends.get(i)); - //} - - // above: import java.util.Iterator; - Iterator itr = friends.iterator(); - while (itr.hasNext()) { - String name = itr.next(); - System.out.println(name); + + 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) { - for (String name : friends) { - System.out.println(name); - } + 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()); + + 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 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() ..."); + printIntList(intList); + System.out.println(); + + System.out.println("Adding 20 to list"); + intList.add(20); + System.out.println("Size: " + intList.size()); + printIntList(intList); + System.out.println(); + + System.out.println("Setting index 8 (#9) to 90"); + intList.set(8, 90); + System.out.println("Size: " + intList.size()); + printIntList(intList); + System.out.println(); + + System.out.println("Adding 40 at index 4"); + intList.add(4,40); + System.out.println("Size: " + intList.size()); + printIntList(intList); + System.out.println(); + + System.out.println("Testing indexOf(item), index of 90 should be 9."); + System.out.println(intList.indexOf(90)); + System.out.println(); + + System.out.println("Testing indexOf(item), index of 3 should be 2."); + System.out.println(intList.indexOf(3)); + System.out.println(); + + System.out.println("Adding 5 to end of list for next test"); + intList.add(5); + printIntList(intList); + System.out.println(); + + 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(); - ListIterator fancyItr = friends.listIterator(); - while (fancyItr.hasNext()) { - String name = fancyItr.next(); - System.out.println(name); + printIntList(intList); + + System.out.println("Testing remove(index), removing index 4 (#40)"); + intList.remove(4); + printIntList(intList); + System.out.println(); + + 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(); + + System.out.println("Testing remove(item), removing #90"); + intList.remove(Integer.valueOf(90)); + + + printIntList(intList); + System.out.println(); + + System.out.println(); + System.out.println("Testing clear(), printed list"); + intList.clear(); + printIntList(intList); + System.out.println(); + + 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(); + + 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(); + + 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); + + + System.out.println("Testing ListIterator forward"); + ListIterator myItr = intList.listIterator(); + while(myItr.hasNext()) { + System.out.print(myItr.next() + " "); } System.out.println(); - while (fancyItr.hasPrevious()) { - String name = fancyItr.previous(); - System.out.println(name); + + System.out.println("Testing in reverse"); + while(myItr.hasPrevious()) { + System.out.print(myItr.previous() + " "); } + System.out.println(); + + 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); + 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(); + + 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"); + 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 index 483ec57..eb3f6e6 100644 --- a/src/edu/greenriver/sdev333/ArrayList.java +++ b/src/edu/greenriver/sdev333/ArrayList.java @@ -3,24 +3,36 @@ import java.util.Iterator; import java.util.ListIterator; +/** + * This class implements the List interface in the Java collections + * package. + * + * @author Jack Ruiz + * + * @param + */ public class ArrayList implements List { - // WE NEED FIELDS!! + // WE NEED FIELDS - // one plain old Java array + // one plain Java array private ItemType[] data; // one int to keep track of size - // size is the # of spots that are used in the data array - // size is DIFFERENT than length + // 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. @@ -39,12 +51,7 @@ public int size() { */ @Override public boolean isEmpty() { - if (size == 0) { - return true; - } - return false; - - // alternate way to write it: return size == 0; + return size == 0; } /** @@ -57,12 +64,11 @@ public boolean isEmpty() { */ @Override public boolean contains(ItemType item) { - int i = indexOf(item); - if (i != -1) { - return true; + if (item == null) { + throw new NullPointerException(); } - return false; + return (indexOf(item) != -1); } /** @@ -75,26 +81,6 @@ public Iterator iterator() { return new OurCustomIterator(); } - private void checkSize() { - if (size == data.length) { - // resize up (double up the array size) - - // Step 1 - create a new larger array - ItemType[] temp = (ItemType[]) new Object[size * 2]; - - // Step 2 - copy items from data to temp - for (int i = 0; i < size; i++) { - temp[i] = data[i]; - } - - // Step 3 - repoint/refererence data to point to new array - data = temp; - - // Optional: - temp = null; - } // end of if (need to resize) - } - /** * Adds the specified item to the collection. * @@ -104,12 +90,34 @@ private void checkSize() { */ @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(); - data[size] = item; - size++; - } // end of method + } + + /* + * 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, @@ -121,13 +129,14 @@ public void add(ItemType item) { */ @Override public void remove(ItemType item) { + if (item == null) { + throw new NullPointerException(); + } + // IN CLASS int i = indexOf(item); if (i != -1) { - // if it's found, use the other remove method to do the work remove(i); } - - } /** @@ -136,7 +145,7 @@ public void remove(ItemType item) { */ @Override public void clear() { - // lazy deletion + // data = (ItemType[]) new Object[data.length]; size = 0; } @@ -151,25 +160,12 @@ public void clear() { @Override public boolean containsAll(Collection otherCollection) { - Iterator itr = (Iterator)otherCollection.iterator(); - while (itr.hasNext()) { - ItemType itemToCheck = itr.next(); - if (!contains(itemToCheck)) { + for (ItemType i: otherCollection) { + if (!contains(i)) return false; - } } return true; - - - //for (ItemType itemToCheck : otherCollection) { - // if (!contains(itemToCheck)) { - // return false; - // } - //} - - //return true; - } /** @@ -179,7 +175,11 @@ public boolean containsAll(Collection otherCollection) { */ @Override public void addAll(Collection otherCollection) { - throw new UnsupportedOperationException("Not gonna do it!"); + if (otherCollection != null) { + for (ItemType i: otherCollection) { + this.add(i); + } + } } /** @@ -192,7 +192,9 @@ public void addAll(Collection otherCollection) { */ @Override public void removeAll(Collection otherCollection) { - + for (ItemType i: otherCollection) { + remove(i); + } } /** @@ -205,7 +207,18 @@ public void removeAll(Collection otherCollection) { */ @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); } /** @@ -218,11 +231,12 @@ public void retainAll(Collection otherCollection) { */ @Override public ItemType get(int index) { - if (index >= size) { + if (validIndex(index)) { + return data[index]; + } + else { throw new IndexOutOfBoundsException("index is beyond size"); } - - return data[index]; } /** @@ -238,11 +252,11 @@ public ItemType get(int index) { */ @Override public void set(int index, ItemType item) { - if (index >= size) { + if (validIndex(index)) { + data[index] = item; + } else { throw new IndexOutOfBoundsException("index is beyond size"); } - - data[index] = item; } /** @@ -259,14 +273,17 @@ public void set(int index, ItemType item) { */ @Override public void add(int index, ItemType item) { - checkSize(); + 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; i >= index + 1; i--) { - data[i] = data[i - 1]; - } + for (int i = size-2; i > index; i--) { + data[i] = data[i-1]; + } - data[index] = item; - size++; + // finally, set the 'added' item to the specified location + set(index, item); + } } /** @@ -279,10 +296,14 @@ public void add(int index, ItemType item) { */ @Override public void remove(int index) { - // shift values left to overwrite the item at index + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(); + } + for (int i = index; i < size - 1; i++) { data[i] = data[i + 1]; } + size--; } @@ -298,14 +319,12 @@ public void remove(int index) { */ @Override public int indexOf(ItemType item) { - + // DID AT HOME for (int i = 0; i < size; i++) { - if (item.equals(data[i])) { + if (data[i].equals(item)) return i; - } } - // if we got here, it wasn't in the array return -1; } @@ -321,7 +340,12 @@ public int indexOf(ItemType item) { */ @Override public int lastIndexOf(ItemType item) { - return 0; + for (int i = size-1; i >= 0; i--) { + if (data[i].equals(item)) + return i; + } + + return -1; } /** @@ -333,11 +357,70 @@ public int lastIndexOf(ItemType item) { */ @Override public ListIterator listIterator() { - return null; + 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() { @@ -355,12 +438,20 @@ public ItemType next() { 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 - lets us go forwards and backwards + + // fancier Iterator that lets us go forwards and backwards private int currentPosition; + private int lastIndexReturned; public SecondCustomIterator() { currentPosition = 0; @@ -368,44 +459,57 @@ public SecondCustomIterator() { @Override public boolean hasNext() { - return false; + return currentPosition < size(); } @Override public ItemType next() { - return null; + ItemType result = get(currentPosition); + lastIndexReturned = currentPosition; + currentPosition++; + return result; } @Override public boolean hasPrevious() { - // hasNext checked currentPosition with size - // hasPrevious check currentPosition against 0 - return false; + return currentPosition > 0; } @Override public ItemType previous() { - return null; + if (currentPosition > 0) { + ItemType result = get(currentPosition - 1); + lastIndexReturned = currentPosition - 1; + return result; + } else { + throw new IndexOutOfBoundsException(); + } } @Override public int nextIndex() { - return 0; + if (currentPosition == size() - 1) + return currentPosition; + else + return currentPosition + 1; } @Override public int previousIndex() { - return 0; + 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 diff --git a/src/edu/greenriver/sdev333/DoublyLinkedList.java b/src/edu/greenriver/sdev333/DoublyLinkedList.java new file mode 100644 index 0000000..2e577e9 --- /dev/null +++ b/src/edu/greenriver/sdev333/DoublyLinkedList.java @@ -0,0 +1,606 @@ +package edu.greenriver.sdev333; + +import java.util.Iterator; +import java.util.ListIterator; + +/** + * This class implements the List interface. + * + * @author Jack Ruiz + */ +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<>(); + } +} \ No newline at end of file diff --git a/src/edu/greenriver/sdev333/SinglyLinkedList.java b/src/edu/greenriver/sdev333/SinglyLinkedList.java index 35b89bb..4ae24c7 100644 --- a/src/edu/greenriver/sdev333/SinglyLinkedList.java +++ b/src/edu/greenriver/sdev333/SinglyLinkedList.java @@ -1,6 +1,5 @@ package edu.greenriver.sdev333; -import javax.naming.OperationNotSupportedException; import java.util.Iterator; import java.util.ListIterator; @@ -8,9 +7,10 @@ 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 classes + // helper/inner class private class Node { ItemType data; Node next; @@ -21,11 +21,55 @@ private class Node { */ public SinglyLinkedList() { // an empty list has no nodes, - // which means it has no head, so set head to null + // 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. * @@ -56,12 +100,7 @@ public boolean isEmpty() { */ @Override public boolean contains(ItemType item) { - // assume indexOf is working... - int position = indexOf(item); - if (position == -1) { - return false; - } - return true; + return false; } /** @@ -71,7 +110,7 @@ public boolean contains(ItemType item) { */ @Override public Iterator iterator() { - return new OurCustomIterator(); + return null; } /** @@ -83,13 +122,19 @@ public Iterator iterator() { */ @Override public void add(ItemType item) { - if (item == null) { - throw new NullPointerException(); + + 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; } - // the index at the end of the list is size - 1 - // example: if list is size 5, last index is 4 - // so we can just insert at the last index - add(size() - 1, item); + + ++size; } /** @@ -102,35 +147,6 @@ public void add(ItemType item) { */ @Override public void remove(ItemType item) { - if (item == null) { - throw new NullPointerException(); - } - - // alternative - easier to write, but less efficient - /* - int position = indexOf(item); - if (position != -1) { - remove(position); - } - */ - - if (head.data == item) { - head = head.next; - size--; - } - else { - Node current = head; - Node previous; - while (current.next != null) { - previous = current; - current = current.next; - - if (current.data.equals(item)) { - previous.next = current.next; - size--; - } - } - } } @@ -164,7 +180,7 @@ public boolean containsAll(Collection otherCollection) { */ @Override public void addAll(Collection otherCollection) { - throw new UnsupportedOperationException(); + } /** @@ -203,21 +219,7 @@ public void retainAll(Collection otherCollection) { */ @Override public ItemType get(int index) { - if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException(); - } - - Node current = head; - int counter = 0; - while (counter != index) { - current = current.next; - counter++; - } - return current.data; - - /*for (int i = 0; i < index; i++) { - current = current.next; - }*/ + return null; } /** @@ -250,39 +252,17 @@ public void set(int index, ItemType item) { */ @Override public void add(int index, ItemType item) { - checkIndex(index); - - if (index == 0) { - // if someone wants to add at the beginning, I need to change the head - Node theNewOne = new Node(); - theNewOne.data = item; - theNewOne.next = head; - - head = theNewOne; - } - else { - Node current = head; - - // stop one before the position I want to insert at - for (int i = 0; i < index - 1; i++) { - current = current.next; - } - - // when I get here, current is pointing the node *BEFORE* the node at the index - Node theNewOne = new Node(); - theNewOne.data = item; - theNewOne.next = current.next; - - current.next = theNewOne; - } - - size++; - } - - private void checkIndex(int index) { - if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException(); - } + 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; } /** @@ -295,22 +275,6 @@ private void checkIndex(int index) { */ @Override public void remove(int index) { - checkIndex(index); - - if (index == 0) { - head = head.next; - } - else { - Node current = head; - for (int i = 0; i < index - 1; i++) { - current = current.next; - } - // when I get here - current is pointing to the node BEFORE the one at index - - current.next = current.next.next; - } - - size--; } @@ -326,18 +290,7 @@ public void remove(int index) { */ @Override public int indexOf(ItemType item) { - int counter = 0; - Node current = head; - while (current != null) { - if (current.data.equals(item)) { - return counter; - } - counter++; - current = current.next; - } - - // if we get here, it's not found - return -1; + return 0; } /** @@ -364,92 +317,6 @@ public int lastIndexOf(ItemType item) { */ @Override public ListIterator listIterator() { - return new OurEnhancedIterator(); + return null; } - - private class OurCustomIterator implements Iterator { - - // field - private Node currentPosition; - - public OurCustomIterator() { - currentPosition = head; - } - - @Override - public boolean hasNext() { - // see if I'm on the last node: if (current.next == null) - // see if I made it past the last node: if (current == null) - if (currentPosition != null) { - return true; - } - return false; - } - - @Override - public ItemType next() { - ItemType result = currentPosition.data; - currentPosition = currentPosition.next; - return result; - } - } - - private class OurEnhancedIterator implements ListIterator { - - private Node currentPosition; - private int currentIndex; - - public OurEnhancedIterator() { - currentPosition = head; - currentIndex = 0; - } - - @Override - public boolean hasNext() { - return currentPosition != null; - } - - @Override - public ItemType next() { - ItemType result = currentPosition.data; - currentPosition = currentPosition.next; - return result; - } - - @Override - public boolean hasPrevious() { - return false; - } - - @Override - public ItemType previous() { - return null; - } - - @Override - public int nextIndex() { - return 0; - } - - @Override - public int previousIndex() { - return 0; - } - - @Override - public void remove() { - - } - - @Override - public void set(ItemType itemType) { - - } - - @Override - public void add(ItemType itemType) { - - } - } - -} +} \ No newline at end of file