Upload
gyles-bond
View
224
Download
0
Embed Size (px)
DESCRIPTION
CS61B L13 Lists (3)Garcia / Yelick Fall 2003 © UCB Encapsulation of Lists The inner ListNode class forms the structure We encapsulate the structure, because: –To preserve invariants on the structure, such as absence of cycles –Without it, the empty list is null, which is not an object can’t ask a list whether it is empty –Without it, you cannot add to the front of the list, if “this” is itself the first node in the list –We can speed up some operations, like size, by adding extra variables (memoizing) –Manipulating pointers is very error-prone, so we only want to write this stuff once and re-use it
Citation preview
CS61B L13 Lists (1) Garcia / Yelick Fall 2003 © UCB
2003-09-29 Dan Garcia (www.cs.berkeley.edu/~ddgarcia)
Kathy Yelick (www.cs.berkeley.edu/~yelick)
inst.eecs.berkeley.edu/~cs61b/www.ucwise.org1 Handout: notes
Computer Science 61BData Structures and Advanced Programming
Lists and Iterators Lecture 14
CS61B L13 Lists (2) Garcia / Yelick Fall 2003 © UCB
Review of List Structurepublic class SimpleList { // private fields in List private int mySize; private ListNode myHead;
private class ListNode { public Object myItem; public ListNode myNext;
public ListNode (Object obj) { myItem = obj; myNext = null;
} public ListNode (Object obj, ListNode next) { myItem = obj; myNext = next; } }}
Inner class
CS61B L13 Lists (3) Garcia / Yelick Fall 2003 © UCB
Encapsulation of Lists• The inner ListNode class forms the structure• We encapsulate the structure, because:
– To preserve invariants on the structure, such as absence of cycles
– Without it, the empty list is null, which is not an object can’t ask a list whether it is empty
– Without it, you cannot add to the front of the list, if “this” is itself the first node in the list
– We can speed up some operations, like size, by adding extra variables (memoizing)
– Manipulating pointers is very error-prone, so we only want to write this stuff once and re-use it
CS61B L13 Lists (4) Garcia / Yelick Fall 2003 © UCB
A Recursive Helper• Define a method within the ListNode class /** Find the node at the given position * @requires this is acyclic * @param pos is the position to find * @return the node at the given position. * @exception NoSuchElementException if pos < 0 or * pos >= #nodes in this */ public ListNode ptrTo (int pos) { if (position < 0) { throw new NoSuchElementException (“at " + pos); } else if (position == 0) { return this; } else if (myNext == null) { throw new NoSuchElementException (“at " + pos); } else { return myNext.ptrTo (position-1); } }
CS61B L13 Lists (5) Garcia / Yelick Fall 2003 © UCB
Methods on a Simple List Classpublic class SimpleList {
public SimpleList ( ) { // ListNode not shown mySize = 0; myHead = null;
}
public int size ( ) { return mySize; }
public void insertFront (Object obj) { myHead = new ListNode (obj, myHead); mySize += 1; } public Object nth (int position) { return myHead.ptrTo (position).myItem; }
private int mySize; private ListNode myHead;
}
CS61B L13 Lists (6) Garcia / Yelick Fall 2003 © UCB
Can add at 1 past end
An Add (at position) Method• A method to add at a given position in the
list /** Insert an object at position n * @param n is the position * @param obj is the object to add * @modifies this * @exception IllegalArgumentException if * n < 0 || n >= size() */ public void add (int n, Object obj) { if (n < 0 || n > size ( )) { throw new IllegalArgumentException (“Add…”);
} else { Idea: use ptrTo to get the node before position
link in the new node on the myNext field Two cases: 1) adding to the beginning 2) adding to the middle (or end) }}
CS61B L13 Lists (7) Garcia / Yelick Fall 2003 © UCB
Adding a Node• The missing code for n>= 1:
myHead.ptrTo(n-1).myNext = new ListNode (obj, node.myNext);
• Example: add(2, new Integer(6)) myHead.ptrTo(2-1) myHead
2 4 8 10
x
• Doesn’t work for n=0, because no node at -1
6
CS61B L13 Lists (8) Garcia / Yelick Fall 2003 © UCB
Sentinels• One solution is to have two cases in the
code (n == 0 and n > 0):– The right approach if your only problem is add– But you end up with these cases in many methods
• A sentinel is an extra element of a list or vector used to protect the others:– It does not hold user data– Its data is not in the abstraction function (toString)
• Common uses:– Put a sentinel at the end to use as stopping criterion
and avoid null check– Put a sentinel at the beginning so every “real” node
has a previousIf loop/control is complicated, consider a sentinel.
CS61B L13 Lists (9) Garcia / Yelick Fall 2003 © UCB
Add with Sentinel Node• Put a sentinel node at the front: public SimpleList ( ) { mySize = 0; myHead = new ListNode(null,null);
}public Object nth (int position) { return myHead.ptrTo (position+1).myItem; }
public void add (int n, Object obj) { if (n < 0 || n > size ( )) { throw new
IllegalArgumentException ("out of range: " + n); } else {
ListNode node = myHead.ptrTo (n); node.myNext = new ListNode (obj, node.myNext); mySize++; }
}
CS61B L13 Lists (10) Garcia / Yelick Fall 2003 © UCB
Performance of SimpleList• This is a nice clean abstraction, but given a
list lst, how does the following perform?for (int i = 0; i < lst.size(); i++) { System.out.println(lst.nth());}
• Cost of nth on an n-element list (if we know nothing about the position passed in) is O(n), proportional to n
• Count # ListNodes touched in each iteration: 2 + 3 + 4 + … + n + (n+1) = n + k = n + n*(n+1)/2 which is O(n2)
nk=1
CS61B L13 Lists (11) Garcia / Yelick Fall 2003 © UCB
Why n*(n+1)/2 ?• What is the sum of the numbers from 1 to
n?• We want to find S in: S = 1 + 2 + 3 + ... + n-1 + n• Can also write this as S = n + n-1 + n-2 + ... + 2 + 1 • Add them to get 2*S = n+1 + n+1 + n+1 + ... + n+1 + n+1 = n*(n+1)• So S = n*(n+1)/2• Alternate proof by area in the G&T book
CS61B L13 Lists (12) Garcia / Yelick Fall 2003 © UCB
Making (some) List Accesses O(1)
• Finding an arbitrary element in a list is O(n); there is nothing we can do about that
• But finding the next element in a list is O(1);– give the user this ability without exposing internals
• Enumerations can do this:– Variable to hold ListNode whose item was just returned– The elements method returns a new Enumeration
myHead
9 12 6
CS61B L13 Lists (13) Garcia / Yelick Fall 2003 © UCB
Enumerations on Listsprivate class ListEnumeration implements Enumeration { public ListEnumeration ( ) { myPosition = myHead; } public boolean hasMoreElements ( ) { return myPosition != null
&& myPosition.myNext != null; } public Object nextElement ( ) { if (!hasMoreElements ( )) { throw new
NoSuchElementException ("List Enum ran out!"); } myPosition = myPosition.myNext;
return myPosition.myItem; } // myPosition is the element just returned by next private ListNode myPosition;}
CS61B L13 Lists (14) Garcia / Yelick Fall 2003 © UCB
Enumerations vs. Iterators• In Java 1.2 and higher, Iterators usually used in
place of Enumerations:– Adds a mutation operation
» remove()– Better names
» hasMoreElements( ) hasNext( )» nextElement( ) next( )
– Implement Iterator interface rather than Enumeration– Import java.util.Iterator– Change return type of elements to Iterator
• The remove operation can be tricky• Otherwise Iterators are similar to Enumerations
CS61B L13 Lists (15) Garcia / Yelick Fall 2003 © UCB
Iterator Interface• Iterator interface in java.util.Iterator:• Method Summary boolean hasNext() Returns true if the iteration has more elements.
Object next() Returns the next element in the iteration.
void remove() Removes from the underlying collection the last element returned by the iterator (optional operation).
CS61B L13 Lists (16) Garcia / Yelick Fall 2003 © UCB
Implementing Remove•Given an inner class as before:
private class SimpleListIterator implements Iterator { public SimpleListIterator( ) { … as before …} public boolean hasNext( ) { … as before… } public Object next( ) { … as before… } private ListNode myPosition;}
•Attempted implementation of remove (version 1)public void remove ( ) { if (myPosition != null) { myPosition.myNext = myPosition.myNext.myNext; mySize--; }}
•Which element does this code remove?
CS61B L13 Lists (17) Garcia / Yelick Fall 2003 © UCB
myPrev myPosition
null
Implementing Remove• The spec says you should remove the element just
returned from next• Keep a pointer to the node before the one to remove
– To remove 9, need a pointer to node with 6– Call this: myPrev (red sleeve in picture, points to ListNode)– Set in Iterator constructor and next
myHead
9 12 6
myPrev myPosition myPositionmyPrev
X
CS61B L13 Lists (18) Garcia / Yelick Fall 2003 © UCB
Code for Iterator with Remove
private class SimpleListIterator implements Iterator { public SimpleListIterator ( ) { myPosition = myHead;
myPrev = null;} public boolean hasNext ( ) { return myPosition != null && myPosition.myNext != null;} public Object next ( ) { if (!hasNext ( )) { throw new NoSuchElementException ("Iter ran out!"); } myPrev = myPosition;
myPosition = myPosition.myNext; Object obj = myPosition.myItem; return obj;}
private ListNode myPosition; private ListNode myPrev; // to be continued
Remove code on next slide
CS61B L13 Lists (19) Garcia / Yelick Fall 2003 © UCB
Code for Iterator with Remove
// Also in the classpublic void remove() {if (myPrev == null) {
throw new IllegalStateException(“next not yet called”); } if (myPosition == null ) { throw new
NoSuchElementException (“Iter ran out!");} else { myPrev.myNext = myPosition.myNext; myPosition = myPosition.myNext; mySize--;
}}
CS61B L13 Lists (20) Garcia / Yelick Fall 2003 © UCB
Interfaces and Missing Method• It doesn’t always make sense to implement
every method in an interface
• If we didn't want to implement remove, for example:
public void remove ( ) { throw new UnsupportedOperationException( "No remove()"); }
• Java documentation convention: interface API says what methods are optional
CS61B L13 Lists (21) Garcia / Yelick Fall 2003 © UCB
Mutation During Iteration•In general, mutating a data structure
while iterating over it is dangerous•Usual conventions:
–Can only mutate with mutation on Iterator, not basic operations on structure (e.g., SimpleList)
–After first mutation, need to quit iterating, I.e., execute a break
–Don’t have multiple iterations going on with the same object, if one will mutate it.
CS61B L13 Lists (22) Garcia / Yelick Fall 2003 © UCB
Peer Instruction
A. The remove operation on ListIter is constant time O(1).
B. If remove is called twice in a row, two consecutive elements from the original list will be removed
C. There is no need to write specification for all of the SimpleListIter methods.
ABC1: FFF2: FFT 3: FTF4: TFF5: FTT6: TFT7: TTF8: TTT
What is the veracity of these statements?
CS61B L13 Lists (23) Garcia / Yelick Fall 2003 © UCB
Fixing the Iterator• In remove, delete the line: myPosition = myPosition.next• And add to remove: if (myPrev != myPosition.next) { throw new IllegalStateException (“already removed current element”); }• In next add: if (myPrev != myPosition.next) { myPrev = myPosition; }
CS61B L13 Lists (24) Garcia / Yelick Fall 2003 © UCB
Administrivia• Reading for Wednesday: Chapter 12• Lab 6: no change in checkoff from previous
labs– Not available yet, but will be soon– Try to get future labs online by Monday at 11am
checkoffs only allowed during current week.• Make sure to read the most current Errata for
proj1
CS61B L13 Lists (25) Garcia / Yelick Fall 2003 © UCB
Project Peer Instruction
How far into the project are you?Use confidence to measure enjoyment!(H = high, <nothing> = medium, L= low)E.g.,: LOVED it, 60% finished, Push: H6
1: 10%2: 20%3: 30%… …8: 80%9: 90%0: FIN