Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
University of Washington, Tacoma TCSS 342, Autumn 2004, Section A Programming Assignment 1 (Linked List Implementation with Iterator) Assigned: Thursday, October 14, 2004 Due: Thursday, October 21, 3:00pm This programming assignment focuses on implementation and efficiency of linked lists and list iterators. This is an individual assignment. It should be turned in online through the course webpage e-submit system. For this program, you will be given an incomplete class MyLinkedList; it is a doubly-linked list with dummy header and tail. It resides in file MyLinkedList.java that contains an almost-complete implementation of the interface java.util.List. This file, along with a testing class, can be downloaded from the course web page. (You should perform your own testing and should not assume that the provided test file is exhaustive.) Your assignment is to complete the implementation as specified below, as well as making a few performanceincreasing optimizations to the MyLinkedList class. A major part of this assignment will be writing a class that represents a birectional list iterator, and using it to implement missing methods from your list. The following methods are already defined for you, with behavior as described in the relevant Java API for the List interface (which can be found at http://java.sun.com/j2se/1.4.2/docs/api/java/util/List.html): public public public public public public public public public public public public public public public public public public public public MyLinkedList() void add(int index, Object element) boolean add(Object element) void addFirst(Object element) void addLast(Object element) void clear() boolean contains(Object element) Object get(int index) int indexOf(Object element) boolean isEmpty() int lastIndexOf(Object element) Object remove(int index) boolean remove(Object element) boolean removeAll(Collection c) Object set(int index, Object value) int size() List subList(int startIndex, int endIndex) Object[] toArray() Object[] toArray(Object[] array) String toString() You must make the following modifications to the MyLinkedList: (not supported) 1. Implement a ListIterator for the MyLinkedList. To implement the listIterator , listIterator(int), and other methods and several other portions of the code for this program, you must write a class that implements the java.util.ListIterator interface. The relevant Java documentation for this interface is available at http://java.sun.com/j2se/1.4.2/docs/api/java/util/ListIterator.html. Implement your list iterator as an inner class inside the MyLinkedList class, so that it has access to the fields and methods of the MyLinkedList object that created it. Your list iterator should only allocate a fixed amount of storage; it may not contain, for example, an array of all the elements in the list. Please put brief comments on your iterator class and its methods. You do not need to use Javadoc-style comments. The ListIterator interface has the following methods. All methods of your list iterator class except its constructor must run in O(1) time. public YourClassName(int index) Constructs your list iterator such that the first element that will be returned by a call to next will be the element at the given index, and a call to the iterator's nextIndex method would return the value index. This constructor is not part of the java.util.ListIterator interface but is recommended. public void add(Object element) Inserts the specified element into the list. The element is inserted immediately before the next element that would be returned by next, if any, and immediately after the next element that would be returned by previous, if any. (If the list contains no elements, the new element becomes the sole element on the list.) The new element is inserted before the implicit cursor: a subsequent call to next would be unaffected. (This call also increases by 1 the value that would be returned by a call to nextIndex.) public boolean hasNext() Returns true if this list iterator has more elements remaining. (In other words, returns true if a call to next would return an element rather than throwing an exception.) public Object next() Returns the next element in the list, and advances the iterator's position by one element. This is the element whose index would currently be returned by nextIndex(), as well as the element that would be returned by a call to get(nextIndex()) on the list itself. This method may be called repeatedly to iterate through the list in a forward direction and return each element of it in forward order. Your implementation should throw a NoSuchElementException if the iterator has already finished iterating over all elements of the list. public int nextIndex() Returns the index of the element that would be returned by a subsequent call to next. This value is always one more than the value that would be returned by previousIndex. Returns the list's size if the list iterator is at the end of the list. Note that calling this method should not actually change the iterator's position. For example, calling listIterator(0).nextIndex() on any list would return the value 0. public boolean hasPrevious() Returns true if this list iterator has elements remaining behind it. (In other words, returns true if a call to previous would return an element rather than throwing an exception.) public Object previous() Returns the previous element in the list, and decreases the iterator's position by one element. This is the element whose index would currently be returned by previousIndex(), as well as the element that would be returned by a call to get(previousIndex()) on the list itself. This method may be called repeatedly to iterate through the list in a reverse direction and return each element of it in reverse order. Your implementation should throw a NoSuchElementException if the iterator is at the beginning of the list. public int previousIndex() Returns the index of the element that would be returned by a subsequent call to previous. This value is always one less than the value that would be returned by nextIndex. Returns -1 if the list iterator is at the beginning of the list. Note that calling this method should not actually change the iterator's position. For example, calling listIterator(0).previousIndex() on any list would return the value -1. public void remove() Removes from the list the last element that was returned by next. You do not need to support the ability to call remove more than once per call to next (that is, you only need to have the ability to remove the last element seen). You also do not need to support removal if your iterator's add method has been called since the last call to next. Signify unsupported removal states by throwing an IllegalStateException. public void set(Object element) Replaces the last element returned by next with the specified element (optional operation). You do not need to support the ability to call set after either remove or add have been called on your iterator after the last call to next. After successfully implementing your list iterator, you should then use it to improve the runtime of the methods described previously. To get an example of how an iterator can be used to write methods such as retainAll, look at the provided version of removeAll as an example. If you want to compare your class's behavior against what is expected, try substituting a java.util.LinkedList for your MyLinkedList in the testing code and re-running it. If you have trouble successfully implementing the iterator, a quick hack to get a ListIterator is the following: ListIterator itr = Arrays.asList(this.toArray()).listIterator(); The code above copies the elements of your MyLinkedList into a temporary second List, and returns a list iterator for this second list. It will work for read-only operations but not for removals or other modifications, because it would modify the second list and not your own. Using hacks like the above are considered unacceptable for this assignment because of their unnecessarily slow runtime (the line above is O(n) because it must copy all the elements of your list.) In general if there is a method that you do not wish to implement right away, right its header and throw an UnsupportedOperationException inside. This will allow your code to compile so that you can test incrementally. 2. Implement the following list of methods, to complete the implementation of java.util.List. For the methods that take a Collection c as an argument, You may assume that this != c, that c != null, and that neither collection will be modified during the execution of your code. Unless specified otherwise, each method should run in O(1) time. public boolean addAll(Collection c) Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator. Returns true if this list changed as a result of the call. This will always be true if c has any elements inside it. Your implementation's runtime should be O(n) where n = c.size(). public boolean addAll(int index, Collection c) Inserts all of the elements in the specified collection into this list, starting at the specified position. Shifts the element currently at that position (if any) and any subsequent elements to the right (increases their indices). The new elements will appear in the list in the order that they are returned by the specified collection's iterator. Returns true if this list changed as a result of the call. This will always be true if c has any elements inside it. Your implementation's runtime should be O(n) where n = index + c.size(). (That is, the runtime should be proportional to the time necessary to advance through your list to the given index, plus the number of elements from c to be added.) public boolean containsAll(Collection c) Returns true if this collection contains all of the elements in the specified collection. Your implementation should iterate over the specified collection c, checking each element returned by the iterator in turn to see if it is contained in this list. If all elements are contained, true is returned, otherwise false. Your implementation's runtime should be O(mn) where m = c.size() and n = this.size(). (That is, the runtime should be proportional to the time necessary to search through your list for each element in c.) public Iterator iterator() Returns an iterator over the elements in this list (in proper sequence). Your implementation should merely return a list iterator over the list that begins at index 0. public ListIterator listIterator() Returns an iterator of the elements in this list (in proper sequence). This operation is the same as creating a list iterator at index 0. public ListIterator listIterator(int index) Returns a list iterator of the elements in this list (in proper sequence), starting at the specified position in this list. The specified index indicates the first element that would be returned by an initial call to the iterator's next method. Your implementation's runtime should be O(n) where n = index. public boolean retainAll(Collection c) Retains only the elements in this list that are contained in the specified collection. In other words, removes from this list all of its elements that are not contained in the specified collection. Your implementation should iterate over this list, checking each element returned by the iterator in turn to see if it is contained in the specified collection. If it is not contained, it is removed from this list with the iterator's remove method. Returns true if this list changed as a result of the call. Your implementation's runtime should be O(mn) where m = c.size() and n = this.size(). (That is, the runtime should be proportional to the time necessary to search through your list to find and remove each element contained in c.) 3. Make modifications to some of the existing methods of the MyLinkedList class to improve their runtime efficiency, as follows: The current implementation of several methods unnecessarily have slow runtime for large-size lists, because they repeatedly call the get method, which is O(n) for n = size(). Modify the following methods so that they complete in the faster time specified, with the correct result. In many cases, the best way to make these modifications is to use your list iterator within your MyLinkedList class's methods. You will be graded both on successfully reducing your runtime and on using the ListIterator to do so when appropriate. These are the methods to modify: public int indexOf(Object element) The current implementation of this method is O(n2), where n = size(). Improve this method's runtime to O(n). public int lastIndexOf(Object element) The current implementation of this method is O(n2), where n = size(). Improve this method's runtime to O(n). Also, change this method to take advantage of the doubly-linked structure of the list. Currently, lastIndex iterates forward starting from the beginning of the list. A better algorithm is to iterate backwards, starting from the end of the list; this way, you can stop iterating as soon as a matching element is found. public Object[] toArray(Object[] array) The current implementation of this method is O(n2), where n = size(). Improve this method's runtime to O(n). public String toString() The current implementation of this method is O(n2), where n = size(). Improve this method's runtime to O(n). Submission and Grading: Submit this assignment online, as with all programming assignments, via the link on the course web site. Turn in your MyLinkedList.java only. The correctness of your program will be graded on matching the expected behavior of the methods to be implemented. To get a good idea of the expected behavior, run testing code on a java.util.LinkedList and then substitute your MyLinkedList, and look for differences. Exceptions should not occur under normal usage except as specified previously. The style and design of your program will be graded on whether you follow the program specification above, whether you implement the interfaces given, the reasonableness of your list algorithms, obeying the Big-Oh runtime requested for each method, the presence of reasonable brief comments in your source code (a short header on each file, each method, and on particularly complex code sections), the use of meaningful identifier names, avoiding redundancy, and general spacing and indentation of your code. This program must be completed individually. It is subject to the plagiarism and conduct rules specified in the course syllabus. You should not look at complete source code for classes that implement List or ListIterator except as shown in the textbook; this includes looking at the Sun Java source code for these classes. If you get help from friends, classmates, books or websites, please cite this in comments in your code.