Download presentation
Presentation is loading. Please wait.
Published byCorey Flowers Modified over 9 years ago
1
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Data Structures for Java William H. Ford William R. Topp Chapter 13 Implementing Iterators Bret Ford © 2005, Prentice Hall
2
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Implementation Design Iterator Implementation Guidelines Iterator Implementation Guidelines A collection class is responsible for implementing the Iterator interface. A collection class is responsible for implementing the Iterator interface. An iterator must be bound to the collection for which it is created. An iterator must be bound to the collection for which it is created. Move the iterator class inside the collection class. This inner class is a member of the collection class. The iterator inner class has access to all of the members of the outer class. Move the iterator class inside the collection class. This inner class is a member of the collection class. The iterator inner class has access to all of the members of the outer class.
3
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Implementation Design (continued) Use the implementaion guidelines with the Bag class where IteratorImpl is the name of the iterator inner class. Use the implementaion guidelines with the Bag class where IteratorImpl is the name of the iterator inner class. Recall that the Bag class has private variables bagArr and bagSize. Recall that the Bag class has private variables bagArr and bagSize. The class IteratorImpl implements the Iterator interface and has access to storage attributes bagArr and bagSize. The class IteratorImpl implements the Iterator interface and has access to storage attributes bagArr and bagSize. An iterator object is created by the factory method iterator() in the Bag class. An iterator object is created by the factory method iterator() in the Bag class.
4
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Implementation Design (continued) public class Bag implements Collection, Iterable { private T[] bagArr; private int bagSize;... private class IteratorImpl implements Iterator {... } } available to IteratorImpl object
5
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Implementation Design (concluded) We must implement We must implement The iterator() method in the collection class to return an iterator object that references the first element in the collection. The iterator() method in the collection class to return an iterator object that references the first element in the collection. The methods hasNext(), next(), and remove() in the iterator class. The methods hasNext(), next(), and remove() in the iterator class.
6
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Bag iterator() // return an instance of IteratorImpl which // implements Iterator public Iterator iterator() { return new IteratorImpl(); }
7
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Variables The design of an iterator class depends on the underlying storage structure of the collection and a scanning strategy for the structure. The design of an iterator class depends on the underlying storage structure of the collection and a scanning strategy for the structure. The Bag class uses an array to store elements, and a natural scanning strategy uses an index to traverse elements in order from 0 to bagSize-1. The Bag class uses an array to store elements, and a natural scanning strategy uses an index to traverse elements in order from 0 to bagSize-1.
8
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Variables (continued) An iterator class needs a variable which identifies the element in the collection that is currently referenced by the iterator. An iterator class needs a variable which identifies the element in the collection that is currently referenced by the iterator. It needs a second variable which identifies the element that was extracted by the most recent call to next(). This is the return value and designates the element which would be deleted by the iterator remove() operation. It needs a second variable which identifies the element that was extracted by the most recent call to next(). This is the return value and designates the element which would be deleted by the iterator remove() operation. The type of the variables depends on the way elements are stored in the collection class. The type of the variables depends on the way elements are stored in the collection class.
9
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Variables (continued) The figure is a view of a Bag iterator which uses next() to advance to the next element in the collection. The variable nextIndex is the current index position of the iterator and the variable lastIndex is the position of the element whose value is extracted by the operation. The figure is a view of a Bag iterator which uses next() to advance to the next element in the collection. The variable nextIndex is the current index position of the iterator and the variable lastIndex is the position of the element whose value is extracted by the operation.
10
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Variables (concluded) Initially there is no last-extracted element and after a call to remove(), the element is deleted. In each case we need to assign lastIndex a value that indicates it is currently invalid awaiting a subsequent call to next(). Initially there is no last-extracted element and after a call to remove(), the element is deleted. In each case we need to assign lastIndex a value that indicates it is currently invalid awaiting a subsequent call to next(). In the Bag iterator class, lastIndex has a value -1 when it is invalid. In the Bag iterator class, lastIndex has a value -1 when it is invalid.
11
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. IteratorImpl Class (Bag inner class) private class IteratorImpl implements Iterator { private nextIndex = 0; private lastIndex = -1; // initially invalid... }
12
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Interface Methods The iterator class must use a scanning algorithm that is consistent with how the collection stores elements. The iterator class must use a scanning algorithm that is consistent with how the collection stores elements. In the Bag class, we use an array scan in the range [0, bagSize) and so hasNext() is false when nextIndex == bagSize. In the Bag class, we use an array scan in the range [0, bagSize) and so hasNext() is false when nextIndex == bagSize. public boolean hasNext() { return nextIndex != bagSize; }
13
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Interface Methods (continued) The method next() must extract the current value, remember where the value is, and then advance the iterator. The method next() must extract the current value, remember where the value is, and then advance the iterator. In the Bag class, update both lastIndex and nextIndex and use the value bagArr[lastIndex] as the return value. In the Bag class, update both lastIndex and nextIndex and use the value bagArr[lastIndex] as the return value. public T next() { // return value at lastIndex lastIndex = nextIndex; // advance nextIndex nextIndex++; return bagArr[lastIndex]; }
14
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Iterator Interface Methods (concluded) An iterator remove() operation is valid only if a prior call to next() is in effect. An iterator remove() operation is valid only if a prior call to next() is in effect. This precondition must be checked. If the operation is not valid, throw an exception. This precondition must be checked. If the operation is not valid, throw an exception. The removal is usually done using a collection class method. The removal is usually done using a collection class method.
15
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Bag Class Iterator remove() If lastIndex == -1, next() has not been called, and a RuntimeException is thrown. If lastIndex == -1, next() has not been called, and a RuntimeException is thrown. Otherwise the private Bag class operation remove() is employed to delete the array element bagArr[lastIndex]. Otherwise the private Bag class operation remove() is employed to delete the array element bagArr[lastIndex]. Set lastIndex is to -1 and move nextIndex back one position. This reflects the fact that the previous element was deleted and the tail of the array was shifted left one position. Set lastIndex is to -1 and move nextIndex back one position. This reflects the fact that the previous element was deleted and the tail of the array was shifted left one position.
16
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Bag Class Iterator remove() (concluded) public void remove() { // check for a missing call to next() if (lastIndex == -1) throw new RuntimeException("Iterator call " + "to next() required before " + "calling remove()"); // use Bag class remove() method Bag.this.remove(arr[lastIndex]); // we did a deletion; indicate this by // setting lastIndex to -1 // nextIndex is reset to the left one position nextIndex--; lastIndex = -1; }
17
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. The LinkedList Iterator Overview A LinkedList collection uses a doubly- linked list as its storage structure. A LinkedList collection uses a doubly- linked list as its storage structure. The elements are DNode objects. The elements are DNode objects. Begin a forward scan at the first element header.next and proceed from node to node using the next reference field. Begin a forward scan at the first element header.next and proceed from node to node using the next reference field. The scan concludes when it reaches the header node. The scan concludes when it reaches the header node.
18
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. The LinkedList Iterator Overview (continued) Use the DNode reference variable nextNode to reflect the position in the doubly-linked list that corresponds to an iterator position in the LinkedList collection. Use the DNode reference variable nextNode to reflect the position in the doubly-linked list that corresponds to an iterator position in the LinkedList collection. The DNode reference variable lastReturned corresponds to the element that was extracted by the most recent call to next(). The DNode reference variable lastReturned corresponds to the element that was extracted by the most recent call to next().
19
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. The LinkedList Iterator Overview (continued) The figure illustrates the relationship between a LinkedList iterator, iter, and the corresponding DNode references lastReturned and nextNode when the iterator calls next(). The figure illustrates the relationship between a LinkedList iterator, iter, and the corresponding DNode references lastReturned and nextNode when the iterator calls next().
20
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. The LinkedList Iterator Overview (continued) The iterator class, which we call IteratorImpl is declared as an inner class within the LinkedList class. The iterator class, which we call IteratorImpl is declared as an inner class within the LinkedList class. IteratorImpl has access to the private variables listSize and header. IteratorImpl has access to the private variables listSize and header. It defines its owns private DNode variables nextNode and lastReturned. It defines its owns private DNode variables nextNode and lastReturned. Initially, nextNode = header.next. Initially, nextNode = header.next. Initially, lastReturned = header to indicate that a remove() operation is invalid. Initially, lastReturned = header to indicate that a remove() operation is invalid.
21
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. The LinkedList Iterator Overview (concluded) public class LinkedList implements List, Iterable { private int listSize; private DNode header;... private class IteratorImpl implements Iterator { private DNode nextNode = header.next; private DNode lastReturned = header; }
22
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. LinkedList Iterator Methods The method hasNext() verifies whether more elements are available to scan. The condition is true if nextNode is not the header; that is, nextNode has not reached the end of the doubly-linked list. The method hasNext() verifies whether more elements are available to scan. The condition is true if nextNode is not the header; that is, nextNode has not reached the end of the doubly-linked list. public boolean hasNext() { // elements remain if nextNode is not the header return nextNode != header; }
23
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. LinkedList Iterator Methods (continued) The method next() first verifies that elements remain in the iteration and throws a NoSuchElementException if the condition is false. Advance nextNode in the doubly-linked list and set lastReturned to reference the previous position. Return the data value in lastReturned. The method next() first verifies that elements remain in the iteration and throws a NoSuchElementException if the condition is false. Advance nextNode in the doubly-linked list and set lastReturned to reference the previous position. Return the data value in lastReturned.
24
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. LinkedList Iterator Methods (continued) // returns the next element in the // iteration; throws a NoSuchElementException // if the iteration has no more elements public T next() { // check if the iteration has another element if (nextNode == header) throw new NoSuchElementException( "Iteration has no more elements"); // save current value of nextNode as lastReturned // then advance nextNode lastReturned = nextNode; nextNode = nextNode.next; // return value of lastReturned return lastReturned.nodeValue; }
25
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. LinkedList Iterator Methods (continued) The method remove() checks that the operation is valid and deletes the node referenced by lastReturned using the private LinkedList method remove(). The variable lastReturned is set to header, indicating that a deletion took place and the size is decremented. The method remove() checks that the operation is valid and deletes the node referenced by lastReturned using the private LinkedList method remove(). The variable lastReturned is set to header, indicating that a deletion took place and the size is decremented.
26
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. LinkedList Iterator Methods (concluded) public void remove() { // check if operation is value; that is, // an intervening call to next() is in effect if (lastReturned == header) throw new IllegalStateException("Iterator " + "call to next() required before " + "calling remove()"); // use collection class remove() LinkedList.this.remove(lastReturned); // reset lastReturned to indicate a subsequent // remove() is invalid lastReturned = header; listSize--; }
27
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Implementing ListIterator Overview Implement the ListIterator() methods by using an inner class ListIteratorImpl that extends IteratorImpl. Implement the ListIterator() methods by using an inner class ListIteratorImpl that extends IteratorImpl. In this way, we can use the already existing implementation of hasNext(), and next() in the superclass. The method remove() requires some additional steps in its implementation, so we override it in the subclass. In this way, we can use the already existing implementation of hasNext(), and next() in the superclass. The method remove() requires some additional steps in its implementation, so we override it in the subclass.
28
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Implementing ListIterator Overview (continued) private class ListIteratorImpl extends IteratorImpl implements ListIterator {... } The ListItertorImpl inner class has no data of its own. It uses the variables nextNode, and lastReturned from the IteratorImpl superclass. The ListItertorImpl inner class has no data of its own. It uses the variables nextNode, and lastReturned from the IteratorImpl superclass.
29
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Constructor A programmer has the option of starting a traversal at the first list element by calling the method listIterator() or of starting a traversal at a particular position by calling listIterator(index). The ListIteratorImpl class must provide a constructor that sets nextNode to reference a specific position. A programmer has the option of starting a traversal at the first list element by calling the method listIterator() or of starting a traversal at a particular position by calling listIterator(index). The ListIteratorImpl class must provide a constructor that sets nextNode to reference a specific position.
30
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Constructor (continued) The constructor takes an integer argument that specifies the starting position. It first verifies that the argument index is within the range (0 ≤ index ≤ listSize) and throws an IndexOutOfBoundsException if it is out of range. It then moves the superclass variable nextNode forward to position index. The constructor takes an integer argument that specifies the starting position. It first verifies that the argument index is within the range (0 ≤ index ≤ listSize) and throws an IndexOutOfBoundsException if it is out of range. It then moves the superclass variable nextNode forward to position index.
31
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Constructor (continued) // create the iterator at position index in the list ListIteratorImpl(int index) { if (index listSize) throw new IndexOutOfBoundsException( "Index: " + index + ", Size: " + listSize); // go to index by moving forward // from the front of the list nextNode = header.next; for (int i=0; i < index; i++) nextNode = nextNode.next; }
32
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Constructor (concluded) The LinkedList methods listIterator() simply create and return an appropriate ListIteratorImpl object. The LinkedList methods listIterator() simply create and return an appropriate ListIteratorImpl object. // returns a list iterator beginning // at position index public ListIterator listIterator(int index) { return new ListIteratorImpl(index); } // returns a list iterator initially // referencing position 0 (default constructor) public ListIterator listIterator() { return new ListIteratorImpl(0); }
33
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods The method hasPrevious() verifies that nextNode.prev is not the header node. The method hasPrevious() verifies that nextNode.prev is not the header node. // returns true if the list has more elements // when moving in the backward direction public boolean hasPrevious() { return nextNode.prev != header; }
34
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods (continued) The method previous() advances the iterator one position in the backward direction. The method previous() advances the iterator one position in the backward direction. After a call to previous(), nextNode and lastReturned reference the same element. After a call to previous(), nextNode and lastReturned reference the same element.
35
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods (continued) // returns the previous element in the list; // throws NoSuchElementException if the // iteration has no previous element public T previous() { // check that a predecessor node exists if (nextNode.prev == header) throw new NoSuchElementException( "Iteration has no more elements"); // move backward one position lastReturned = nextNode = nextNode.prev; return lastReturned.nodeValue; }
36
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods (continued) Override remove() in the IteratorImpl superclass to account for the presence of the method previous(). lastReturned can equal nextNode if previous() was called. When this happens, remove() must advance nextNode to the successor of the deleted node. Override remove() in the IteratorImpl superclass to account for the presence of the method previous(). lastReturned can equal nextNode if previous() was called. When this happens, remove() must advance nextNode to the successor of the deleted node.
37
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods (continued) public void remove() { // check for a missing call to next() or previous() if (lastReturned == header) throw new IllegalStateException( "ListIterator call to next() or " + "previous() required before " + "calling remove()"); // use private LinkedList collection // class remove() method LinkedList.this.remove(lastReturned); listSize--;
38
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods (continued) // lastReturned can equal nextNode if // previous() was called; in this case, // move nextNode forward one node if (lastReturned == nextNode) nextNode = nextNode.next; // the list is modified so set lastReturned to header lastReturned = header; }
39
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods (continued) The method add() inserts an item into the list immediately before the node nextNode. The method add() inserts an item into the list immediately before the node nextNode. This task is accomplished by the LinkedList private method addBefore() with nextNode and the item as arguments. This task is accomplished by the LinkedList private method addBefore() with nextNode and the item as arguments. Until next() or previous() is called, no calls to set(), or remove() are allowed. Assign header to the variable lastReturned and then increment listSize. Until next() or previous() is called, no calls to set(), or remove() are allowed. Assign header to the variable lastReturned and then increment listSize.
40
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods (continued) public void add(T item) { checkIteratorState(); // insert item before nextNode LinkedList.this.addBefore(nextNode, item); // set lastReturned to header to invalidate // a call to set() without an intervening // call to next() or previous() lastReturned = header; listSize++; }
41
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods (continued) To implement set(), verify that a prior call to next() or previous() was made since the last add() or remove() operation. The variable lastReturned references the node containing the value returned by next() or previous(). Assign item to lastReturned.nodeValue. To implement set(), verify that a prior call to next() or previous() was made since the last add() or remove() operation. The variable lastReturned references the node containing the value returned by next() or previous(). Assign item to lastReturned.nodeValue.
42
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. ListIterator Public Methods (concluded) public void set(T item) { if (lastReturned == header) throw new IllegalStateException( "Iterator call to next() or previous() " + "required before calling set()"); lastReturned.nodeValue = item; }
43
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Fail-Fast Iterators An iterator may be actively scanning a collection when intervening collection class methods add or remove an element. For instance, the remove() operation may delete the element currently referenced by the iterator. For an iterator to function properly, it must assume that forces outside of its control do not modify the collection. An iterator may be actively scanning a collection when intervening collection class methods add or remove an element. For instance, the remove() operation may delete the element currently referenced by the iterator. For an iterator to function properly, it must assume that forces outside of its control do not modify the collection.
44
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Fail-Fast Iterators (continued) Define an integer variable modCount, initially 0, in the collection class. Increment it whenever a collection method modifies the collection. Define an integer variable modCount, initially 0, in the collection class. Increment it whenever a collection method modifies the collection. An iterator has its own instance variable called expectedModCount. When the iterator is created, the constructor assigns to expectedModCount the current value of the list variable modCount. An iterator has its own instance variable called expectedModCount. When the iterator is created, the constructor assigns to expectedModCount the current value of the list variable modCount.
45
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Fail-Fast Iterators (continued) Before executing the operations next() and remove(), the iterator first compares expectedModCount with the actual value of modCount. If they are not the same, then the iterator recognizes that some operation modified the collection and potentially invalidated the iterator. Before executing the operations next() and remove(), the iterator first compares expectedModCount with the actual value of modCount. If they are not the same, then the iterator recognizes that some operation modified the collection and potentially invalidated the iterator.
46
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Fail-Fast Iterators (continued) The iterator add() and remove() methods, increment the variable modCount and assign the new value to the local variable expectedModCount. The iterator add() and remove() methods, increment the variable modCount and assign the new value to the local variable expectedModCount. The iterator methods next(), remove() previous() and add() call the utility method checkIteratorState() which throws ConcurrentModificationException if expectedModCount ≠ modCount. If the two variables are equal, the iterator is in a consistent state. The iterator methods next(), remove() previous() and add() call the utility method checkIteratorState() which throws ConcurrentModificationException if expectedModCount ≠ modCount. If the two variables are equal, the iterator is in a consistent state.
47
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Fail-Fast Iterators (continued) public void checkIteratorState() { if (expectedModCount != modCount) throw new ConcurrentModificationException( "Inconsistent iterator"); }
48
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Fail-Fast Iterators (continued) A complete implementation of the iterator remove() method includes post deletion housekeeping that updates both modCount and expectedModCount; A complete implementation of the iterator remove() method includes post deletion housekeeping that updates both modCount and expectedModCount;
49
© 2005 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. Fail-Fast Iterators (concluded) public void remove() { // check the state of the iterator checkIteratorState(); // check that the remove() operation is // valid and delete the element extracted // by the most recent call to next()... // the list is modified modCount++; expectedModCount = modCount; }
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.