List ADT. B/W Confirming Pages

Similar documents
Linked List. ape hen dog cat fox. tail. head. count 5

Queue ADT. B/W Confirming Pages

CSC 1052 Algorithms & Data Structures II: Lists

Implementing a List in Java. CSE 143 Java. Just an Illusion? List Interface (review) Using an Array to Implement a List.

ITI Introduction to Computing II

Programming II (CS300)

Stack ADT. B/W Confirming Pages

Programming II (CS300)

Implementing a List in Java. CSE 143 Java. List Interface (review) Just an Illusion? Using an Array to Implement a List.

CSE 143 Lecture 26. Advanced collection classes. (ADTs; abstract classes; inner classes; generics; iterators) read 11.1, 9.6, ,

Computer Science 62. Bruce/Mawhorter Fall 16. Midterm Examination. October 5, Question Points Score TOTAL 52 SOLUTIONS. Your name (Please print)

CS 151. Linked Lists, Recursively Implemented. Wednesday, October 3, 12

Implementation. Learn how to implement the List interface Understand the efficiency trade-offs between the ArrayList and LinkedList implementations

CS201 ArrayLists, Generics, and Dynamic Data Structures (Chapters 14, 15)

CSC 172 Data Structures and Algorithms. Lecture #9 Spring 2018

A Linked Structure. Chapter 17

COMP200 GENERICS. OOP using Java, from slides by Shayan Javed

CSC 172 Data Structures and Algorithms. Lecture #8 Spring 2018

An Introduction to Data Structures

Linked Lists. Chapter 12.3 in Savitch

Arrays and ArrayLists. David Greenstein Monta Vista High School

CSCI 200 Lab 3 Using and implementing sets

Class 26: Linked Lists

An Activation Record for Simple Subprograms. Activation Record for a Language with Stack-Dynamic Local Variables

Array Based Lists. Collections

Arrays.

Collections and Iterators. Collections

Introduction to Computer Science II CS S-20 Linked Lists III

Recursive Objects. Singly Linked List (Part 2)

What is an Iterator? An iterator is an abstract data type that allows us to iterate through the elements of a collection one by one

ADT Stack. Inserting and deleting elements occurs at the top of Stack S. top. bottom. Stack S

CS Introduction to Data Structures Week 1 Thursday

EECS 2011 M: Fundamentals of Data Structures

Chapter 17: Linked Lists

Implementing a List in Java. CSC 143 Java. List Interface (review) Just an Illusion? Using an Array to Implement a List CSC

CSC 321: Data Structures. Fall 2017

Linked List Nodes (reminder)

CE204 Data Structures and Algorithms Part 2

CS 112 Introduction to Computing II. Wayne Snyder Computer Science Department Boston University

What is the Java Collections Framework?

Linked Lists. Linked List Nodes. Walls and Mirrors Chapter 5 10/25/12. A linked list is a collection of Nodes: item next -3.

The ArrayList class CSC 123 Fall 2018 Howard Rosenthal

Problem 1: Building and testing your own linked indexed list

JAVA COLLECTION FRAMEWORK & SETS

16. Dynamic Data Structures

Data Structures and Algorithms

11/2/ Dynamic Data Structures & Generics. Objectives. Array-Based Data Structures: Outline. Harald Gall, Prof. Dr.

CMSC 206: Data Structures Final Exam Reference May 2018

January 24, Abstract Data Types (ADTs) An ADT is an abstraction of a data structure.

CS S-05 Abstract Data Types and Lists 1

DNHI Homework 3 Solutions List, Stacs and Queues

Introduction. Reference

CSE 143. Lecture 7: Linked List Basics reading: 16.2

Introduction to Computer Science II CS S-18 Linked Lists

Lists. CITS2200 Data Structures and Algorithms. Topic 9

CS 61B Data Structures and Programming Methodology. June David Sun

2. The actual object type stored in an object of type CollectionClassName<E> is specified when the object is created.

Standard ADTs. Lecture 19 CS2110 Summer 2009

LINKED LISTS cs2420 Introduction to Algorithms and Data Structures Spring 2015

CS S-20 Linked Lists III 1. We can then use the next pointer of the previous node to do removal (example on board)

CSC 321: Data Structures. Fall 2013

Review: List Implementations. CSE 143 Java. Links. A Different Strategy: Lists via Links. Linked Links. CSE143 Au List

Arrays. Chapter Arrays What is an Array?

Arrays and Linked Lists

INTRODUCTION TO DATA AND PROCEDURE

Stacks (5.1) Abstract Data Types (ADTs) CSE 2011 Winter 2011

Introduction to Linked Data Structures

Java Review: Objects

COMP 250 Winter generic types, doubly linked lists Jan. 28, 2016

Data abstractions: ADTs Invariants, Abstraction function. Lecture 4: OOP, autumn 2003

Specifications for the ADT List Ali list provides a way to organize data List of students List of sales List of lists

Recursion (Part 3) 1

Outline. iterator review iterator implementation the Java foreach statement testing

Exceptions and Design

package weiss.util; // Fig , pg // Fig 6.16,6.17, pg package weiss.util;

Lecture 4. The Java Collections Framework

Insertions and removals follow the Fist-In First-Out rule: Insertions: at the rear of the queue Removals: at the front of the queue

Insertion Sort: an algorithm for sorting an array

Abstract Data Types. Data Str. Client Prog. Add. Rem. Find. Show. 01/22/04 Lecture 4 1

The Java Collections Framework. Chapters 7.5

Lists. The List ADT. Reading: Textbook Sections

Lists, Stacks, and Queues

Lecture 3 Linear Data Structures: Arrays, Array Lists, Stacks, Queues and Linked Lists

CSC 321: Data Structures. Fall 2012

DM537 Object-Oriented Programming. Peter Schneider-Kamp.

Queues. CITS2200 Data Structures and Algorithms. Topic 5

Introduction to Computing II (ITI 1121) Final Examination

DM550 / DM857 Introduction to Programming. Peter Schneider-Kamp

ADTs, Arrays, Linked Lists

DM550 / DM857 Introduction to Programming. Peter Schneider-Kamp

Implementing Lists, Stacks, Queues, and Priority Queues

DM503 Programming B. Peter Schneider-Kamp.

List ADT. Announcements. The List interface. Implementing the List ADT

CS/CE 2336 Computer Science II

Dynamic Data Structures and Generics

Lecture 6: ArrayList Implementation

FORTH SEMESTER DIPLOMA EXAMINATION IN ENGINEERING/ TECHNOLIGY- OCTOBER, 2012 DATA STRUCTURE

Collections, Maps and Generics

Computer Science 62. Midterm Examination

The list abstract data type defined a number of operations that all list-like objects ought to implement:

Transcription:

wu3399_ch8.qxd //7 :37 Page 98 8 List ADT O b j e c t i v e s After you have read and studied this chapter, you should be able to Describe the key features of the List ADT. the List ADT using an array and Implement linked list. Describe and implement the iterator pattern. the key differences between the array Explain and linked implementations of the List ADT. 98

wu3399_ch8.qxd //7 :37 Page 98 98 Chapter 8 List ADT I n t r o d u c t i o n We introduced the concept of linked lists in Chapter 6 and provided the fundamentals of manipulating links. And, in Chapter 7, we introduced the generics feature of Java 5. and used it in defining the SimpleLinkedList class that provides a higher-level abtraction to the client programmers. Using a SimpleLinkedList, the client programmers do not have to deal directly with the linked nodes. Instead, they deal strictly with list objects. The fact that the linked nodes are used in implementation is hidden from the client programmers. This embodies the software engineering principle of information hiding. In this chapter, we will expand this concept further by introducing an abstract data type (ADT). ADTs are reusable software components that support reliable and flexible software construction. abstract data An abstract data type (ADT) is a mathematical specification of a set of data type (ADT) and the corresponding set of operations performed on those data. The key point is that an ADT does not specify how the set of data is actually represented in memory or how the set of operations is implemented. Nice examples of ADTs can be found in the Java Collections Framework. When we look in the java.util package, for example, we see the Java interface List and two classes that implement the List interface. The List interface represents the List ADT, and the two classes ArrayList and LinkedList implement the List ADT. The ArrayList uses an array, and the LinkedList uses linked nodes to implement the List ADT, respectively. To study how the ADT is defined and implemented, we will create our own List ADT and provide two implementations in this chapter which we model after the java.util.list interface and its two implementations. Ours is a much simplified version of those in the java.util package. In Chapters 9 and, we will study the Stack and Queue ADTs, respectively. list ADT 8. The List ADT A list is a linearly ordered collection of elements. Figure 8. shows a sample list, named samplelist, with five elements and another list, named, with five three-letter animal names (String objects). Mathematically, we can designate samplelist as samplelist = ( L o, L, L, L 3, L 4 ) linear ordering duplicate elements Elements in a list are said to be linearly ordered. This means L comes before L and L comes before L, and so forth. For the sample list, the first element is L and the last element is L 4. Note that we are using the zero-based indexing. Elements in a list do not have to be distinct; i.e., duplicate elements are

wu3399_ch8.qxd //7 :37 Page 983 8. The List ADT 983 This value indicates the position of an element in the list. samplelist 3 4 L L L L 3 L 4 This line indicates that the list elements are connected in a linear sequence. 3 4 "dog" "dog" "eel" Notice that the list elements do not have to be unique. Figure 8. A generic list named samplelist with five elements and a list of three-letter animals, named. null elements add allowed. Two objects o and o are considered duplicates if o.equals(o) is true. In the sample list, we see that L and L 3 are duplicates. A list also allows multiple null elements. We will discuss more about the impact of duplicate and null elements in the implementation sections. In the remainder of this section, we will describe the operations of the List ADT. The add operation adds a new element to a list. There are two versions: The first one adds a new element at the end of the list. The second one adds a new element at the designated position in the list. For the second version, all elements in that and higher positions will be shifted to a position one index higher; that is, an element at position i will be shifted to position i. If the given position is a negative value, or larger than the current size of the list, then the index out-of-bound exception will be thrown. Figure 8. illustrates the second version of the add operation.

wu3399_ch8.qxd //7 :37 Page 984 984 Chapter 8 List ADT Before "dog" 3 add(, gnu ) After 3 4 "gnu" "dog" Before "dog" 3 add(5, "gnu") throws <index-out-of-bounds-exception> After "dog" 3 No structural change to the list Figure 8. Sample version add operations on. clear contains get The clear operation removes all elements in the list, which results in an empty list. Figure 8.3 illustrates the clear operation. The contains operation returns true if a specified element is included in the list. Otherwise, false is returned. Notice that there could be duplicate objects. The search will stop immediately after the first match, and true is returned. Figure 8.4 illustrates the contains operation. The get operation returns the element stored at the designated position. If the given position is outside of a valid range less than or greater than or equal to the size of the list an index out-of-bound exception is thrown. The get operation is a read-only operation. It does not remove the element, so the list remains the same after the get operation. Figure 8.5 illustrates the get operation.

wu3399_ch8.qxd //7 :37 Page 985 8. The List ADT 985 Before "dog" 3 clear( ) After Figure 8.3 The effect of the clear operation on the list. Before "dog" 3 contains("gnu") returns false After "dog" 3 No structural change to the list Before "dog" 3 contains() returns true After "dog" 3 No structural change to the list Figure 8.4 Sample contains operations on the list.

wu3399_ch8.qxd //7 :37 Page 986 986 Chapter 8 List ADT Before "dog" 3 get() returns dog After "dog" 3 No structural change to the list Before "dog" 3 get(4) throws <index-out-of-bounds-exception> After "dog" 3 No structural change to the list Figure 8.5 Sample get operations on the list. indexof isempty remove The indexof operation returns the position of the specified object in the list. If the specified object is not in the list, then NOT_FOUND ( ) is returned. If there are duplicates, then the position of the first match is returned. Figure 8.6 illustrates the indexof operation. The isempty operation returns true if the list is empty. Otherwise, false is returned. Figure 8.7 illustrates the isempty operation. There are two versions of the remove operation. In the first version, we specify the element to remove by passing its position; in the second version, we specify the element to remove by passing the element itself. The first version returns the element removed from the list. It throws an index out-of-bound exception if the index i is outside the valid range of and the size of the list minus, that is, i size.

wu3399_ch8.qxd //7 :37 Page 987 8. The List ADT 987 Before "dog" 3 indexof("gnu") returns NOT_FOUND ( ) After "dog" 3 No structural change to the list Before "dog" 3 indexof("dog") returns After "dog" 3 No structural change to the list Figure 8.6 Sample indexof operations on the list. set size The second version removes the element and returns true. If the designated element is not found, then the list remains the same and false is returned. If any duplicates exist, then the first element in the list is removed. In both versions, if an element is successfully removed, then all elements in the position higher than the position of the removed element will be shifted to a position one index lower; that is, elements at position i will be shifted to position i. Figure 8.8 illustrates both types of removal operations. The set operation replaces the element at the designated position with the given element. If the operation is successful, then the operation returns the element previously stored in the designated position. If the designated position is outside of a valid range, then an index out-of-bound exception is thrown. Figure 8.9 illustrates the set operations. The size operation returns the size of the list. Figure 8. illustrates the size operation.

wu3399_ch8.qxd //7 :37 Page 988 988 Chapter 8 List ADT Before "dog" 3 isempty( ) returns false After "dog" 3 No structural change to the list Before isempty( ) returns true After No structural change to the list Figure 8.7 Sample isempty operations on the list. 8. The List Interface We will use a Java interface to define the List ADT. To avoid confusion with the java.util classes, we will prefix the name of the interfaces and classes we define here with NPS (NPS stands for the author s affiliation, Naval Postgraduate School, in Monterey, California). In the NPSList interface definition, we use the generics feature introduced in Chapter 7. Formalizing what we have presented in Section 8., we have the following definition, and Table 8. summarizes the methods: NPSList package edu.nps.util; interface NPSList<E> { public void add(e item); public void add(int index, E item) throws IndexOutOfBoundsException;

wu3399_ch8.qxd //7 :37 Page 989 8. The List Interface 989 Before "gnu" 3 "dog" 4 remove() returns gnu After "dog" 3 Before "gnu" 3 "dog" 4 remove( gnu ) returns true After "dog" 3 Figure 8.8 Sample remove operations on the list. public void clear( ); public boolean contains(e item); public E get(int index) throws IndexOutOfBoundsException; public int indexof(e item); public boolean isempty( ); public E remove(int index)throws IndexOutOfBoundsException; public boolean remove(e item); public E set(int index, E item) throws IndexOutOfBoundsException; public int size( );

wu3399_ch8.qxd //7 :37 Page 99 99 Chapter 8 List ADT Before "dog" 3 set(, "fox") returns ape After "fox" "dog" 3 Before "dog" 3 set(4, "fox") throws <index-out-of-bounds-exception> After "dog" 3 No structural change to the list Figure 8.9 Sample set operations on the list. Before "dog" 3 size( ) returns 4 After "dog" 3 No structural change to the list Figure 8. A sample size operation on the list.

wu3399_ch8.qxd //7 :37 Page 99 8. The List Interface 99 Table 8. The public methods of the list interface. The identifier E is the parameterized type that will be replaced by the actual type such as String and Person Table Interface: NPSList void add( E item ) Adds the item to the end of the list. void add( int index, E item ) throws IndexOutOfBoundsException Adds the item at the specified index position. If the value for index is less than or larger than the size of the list, an IndexOutOfBoundsException is thrown. void clear( ) Empties the list. After the clear method is called, the method isempty will return true. boolean contains( E item ) Returns true if the item is in the list. Otherwise, returns false.if the list is empty, the result is false. E get( int index ) throws IndexOutOfBoundsException Returns the item at the specified index position. Notice that the item is not removed from the list. int indexof( E item ) Returns the index position of the specified item in the list.the value NOT_FOUND (-) is returned when the item is not in the list. boolean isempty( ) Returns true if the list is empty. Otherwise, returns false. E remove( int index ) throws IndexOutOfBoundsException Removes the item at the index position from the list. If the specified index value is less than or greater than size( )-, an IndexOutOfBoundsException is thrown. boolean remove( E item ) Removes the item from the list and returns true.returns false if the item is not found. void set( int index, E item ) throws IndexOutOfBoundsException Replaces the item at the index position with the passed item. If the index is less than or greater than size( ) -, an IndexOutOfBoundsException is thrown. int size( ) Returns the number of items in the list.

wu3399_ch8.qxd //7 :37 Page 99 99 Chapter 8 List ADT We will define two classes NPSArrayList and NPSLinkedList in Sections 8.3 and 8.4. A typical way to declare and create an NPSList object is as follows: NPSList<Person> personlist = new NPSArrayList<Person>( ); NPSList<String> stringlist = new NPSLinkedList<String>( ); The first is a (homogeneous) list of Person objects, and the second is a list of String objects. 8.3 The Array Implementation of the List ADT There are two basic approaches in implementing the List ADT array and linkedlist implementions. In this section, we will implement the list interface by using an array. The linked-list implementation is presented in Section 8.4. For all our implementations, we will use the generics feature so the list members will be homogeneous. To illustrate the list operations with concrete examples, we will use String objects as list members in the following discussion. Figure 8. illustrates the array implementation of a list. The NPSArrayList Class We use an array to store the elements and an int variable to keep track of the number of elements currently in the list. These members are declared as private E[] element; private int count; and initialized as element = (E[]) new Object[DEFAULT_SIZE]; count = ; ADT List: = (,,, "eel" ) Array Implementation: :NPSArrayList element 3 4... n- count 4 :String :String :String :String "eel" Figure 8. An array implementation of the list.

wu3399_ch8.qxd //7 :37 Page 993 8.3 The Array Implementation of the List ADT 993 add in a constructor. We assume the class constant DEFAULT_SIZE is assigned some arbitrary integer. Notice that we first create an array of Object and then typecast it to an array of E, the type parameter. This is necessary because it is not allowed to create an array of generic type. Adding an element at the end of the list can be achieved very easily. We add a new element at the count position and increment the count by. The only complication is the overflow condition. The expand method is used to handle the overflow condition. We detect the overflow condition when the value for count is equal to the length of the element array. Here s the version add method: public void add(e item) { if (count == element.length) { expand( ); element[count] = item; count++; See the full source code listing at the end of this section for the expand method. Instead of implementing the first add method explicitly as shown, we can implement it by simply calling the second add method as public void add(e item) { add(count, item); because the value of count is also the index position of the next available slot in the array, i.e., the end of the list, to add an item. Now, let s see how we can implement the second version of the add method. To insert an element at position i, we must shift current elements at positions i to count- one position to the right to positions i+,..., count, respectively. If an invalid value is given for the position, then an index out-of-bound exception is thrown. Here s the method: public void add(int index, E item) throws IndexOutOfBoundsException { checkinsertposition(index, size()); if (count == element.length) { expand( ); //shift one position to the right for (int i = count; i > index; i--) { element[i] = element[i-]; element[index] = item; count++;

wu3399_ch8.qxd //7 :37 Page 994 994 Chapter 8 List ADT The private method checkinsertposition verifies the validity of index. If it is outside the valid range, an IndexOutOfBoundsException is thrown. The method is defined as follows: private void checkinsertposition(int index) { if (index < ) { throw new IndexOutOfBoundsException( "Negative index of " + index + " is invalid"); else if (index > size()) { throw new IndexOutOfBoundsException(index + " is larger than valid upper bound" + size()); clear The size method returns the number of elements in the list (the method is defined at the end of this section). We will set element[i] to null, where i=,..., count-, sothe objects referenced by element[i] will be garbage-collected. We will then reset the count variable to. public void clear( ) { for (int i = ; i < count; i++) { element[i] = null; count = ; contains We implement this method by using the indexof method. If the indexof method returns a value other than NOT_FOUND (-), then the specified object is in the list, so the contains method returns true. If the indexof method returns NOT_FOUND, then the contains method returns false. public boolean contains(e item) { boolean result = true; int loc = indexof(item); if (loc == NOT_FOUND) { result = false; NOT_FOUND is a class constant. return result;

wu3399_ch8.qxd //7 :37 Page 995 8.3 The Array Implementation of the List ADT 995 get Because we are using an array, this method is straightforward. All we have to do is to return an object at position index of the element array, after confirming that the value for index is valid. Here s the method: public E get(int index) throws IndexOutOfBoundsException { checkaccessposition(index); return element[index]; The private method checkaccessposition ensures that the given index specifies a valid position for accessing an element. If it is outside the valid range, an IndexOutOfBoundsException is thrown. Here s the method: private void checkaccessposition(int index) { if (size() == ) { throw new IndexOutOfBoundsException( "Index " + index + " is invalid. List is empty."); else if (index < ) { throw new IndexOutOfBoundsException( "Negative index of " + index + " is invalid"); else if (index > size()-) { throw new IndexOutOfBoundsException(index + " is larger than valid upper bound" + (size()-)); indexof This method scans the list from the beginning and stops when the first match is located. If the specified object is not in the list, then NOT_FOUND (-) is returned. For this method to work properly, the elements in the list must support the equals method, which we will use to locate the matching element. public int indexof(e item) { int loc = ; while (loc < count &&!element[loc].equals(item)) { loc++; if (loc == count) { loc = NOT_FOUND; return loc;

wu3399_ch8.qxd //7 :37 Page 996 996 Chapter 8 List ADT isempty This method is also straightforward. We just check the value of the count variable. public boolean isempty( ) { return (count == ); remove After the element at position i is removed, we must shift current elements at positions i+ to count one position to the left, to positions i,..., count-, respectively. And, we decrement the count variable by. public E remove(int index) throws IndexOutOfBoundsException { checkaccessposition(index); E item = element[index]; //shift one position to the left for (int i = index; i < count; i++) { element[i] = element[i+]; element[count] = null; count--; return item; The second version of remove requires a routine to find the index of the item to be removed. Once we get the index of an object to remove, we call the first remove method to remove it. If there are any duplicates, then only the first match is removed. If the passed item is not found, then nothing happens. public boolean remove(e item) { int loc = indexof(item); if (loc == NOT_FOUND) { return false; else { remove(loc); return true; set The set method replaces an object at the specified index position with the passed object. If the index is invalid, an index out-of-bound error is thrown. If the

wu3399_ch8.qxd //7 :37 Page 997 8.3 The Array Implementation of the List ADT 997 operation is successful, then the method returns the previous object in the index position. public E set(int index, E item) throws IndexOutOfBoundsException { checkaccessposition(index); E old = element[index]; element[index] = item; return old; size This method is straightforward. We simply return the value of the count variable. public int size( ) { return count; We are now ready to list the complete NPSArrayList class. In the source code listing, we do not show any javadoc comments in order to keep the listing to a manageable size. The actual source code includes the full javadoc comments. NPSArrayList package edu.nps.util; public class NPSArrayList<E> implements NPSList<E> { public static final int DEFAULT_SIZE = 5; public static final int NOT_FOUND = -; private E[] element; private int count; public NPSArrayList( ) { this(default_size); Constructors public NPSArrayList(int size) { if (size <= ) { throw new IllegalArgumentException( "Initial capacity must be positive" ); element = (E[]) new Object[size]; count = ;

wu3399_ch8.qxd //7 :37 Page 998 998 Chapter 8 List ADT public void add(e item) { if (count == element.length) { expand( ); add element[count] = item; count++; public void add(int index, E item) throws IndexOutOfBoundsException { checkinsertposition(index); add if (count == element.length) { expand( ); //shift one position to the right for (int i = count; i > index; i--) { element[i] = element[i-]; element[index] = item; count++; public void clear( ) { clear for(int i = ; i < count; i++) { element[i] = null; count = ; public boolean contains(e item) { contains boolean result = true; int loc = indexof(item); if (loc == NOT_FOUND) { result = false; return result; public E get(int index) throws IndexOutOfBoundsException { checkaccessposition(index); get return element[index];

wu3399_ch8.qxd //7 :37 Page 999 8.3 The Array Implementation of the List ADT 999 public int indexof(e item) { int loc = ; indexof while (loc < count &&!element[loc].equals(item)) { loc++; if (loc == count) { loc = NOT_FOUND; return loc; public boolean isempty( ) { isempty return (count == ); public E remove(int index) throws IndexOutOfBoundsException { checkaccessposition(index); remove E item = element[index]; //shift one position to the left for (int i = index; i < count; i++) { element[i] = element[i+]; element[count] = null; count--; return item; public boolean remove(e item) { remove int loc = indexof(item); if (loc == NOT_FOUND) { return false; else { remove(loc); return true; public E set(int index, E item) throws IndexOutOfBoundsException { checkaccessposition(index); set

wu3399_ch8.qxd //7 :37 Page Chapter 8 List ADT E old = element[index]; element[index] = item; return old; public int size( ) { size return count; private void checkaccessposition(int index) { checkaccessposition if (size() == ) { throw new IndexOutOfBoundsException( "Index " + index + " is invalid. List is empty."); else if (index < ) { throw new IndexOutOfBoundsException("Negative index of" + index + "is invalid"); else if (index > size()-) { throw new IndexOutOfBoundsException(index + "is larger than valid upper bound" + (size()-)); private void checkinsertposition(int index) { checkinsertposition if (index < ) { throw new IndexOutOfBoundsException( "Negative index of " + index + " is invalid"); else if (index > size()) { throw new IndexOutOfBoundsException(index + " is larger than valid upper bound" + size()); private void expand( ) { expand //create a new array whose size is 5% of //the current array int newlength = (int) (.5 * element.length); E[] temp = (E[]) new Object[newLength];

wu3399_ch8.qxd //7 :37 Page 8.4 The Linked-List Implementation of the List ADT //now copy the data to the new array for (int i = ; i < element.length; i++) { temp[i] = element[i]; //finally set the variable entry to point to the new array element = temp; 8.4 The Linked-List Implementation of the List ADT With the array implementation, a whole block of memory is allocated at once. When an overflow condition occurs, a new larger block of memory is allocated and the contents of the original array are copied to the new array. The original array will eventually get garbage-collected when the data member element is set to refer to the new array. Instead of allocating a large block of memory, the linked implementation allocates a small amount of memory that is just large enough for a single element. In general, this finer granularity of memory allocation leads to a more efficient use of memory. These points were discussed in detail in Chapter 6. In this section, we will describe how the linked-list implementation works. Figure 8. illustrates the linked implementation of a list. ADT List: = (,,, "eel" ) Linked-List Implementation: :NPSLinkedList tail head count 4 :String :String :String :String "eel" Figure 8. A linked-list implementation of the list.

wu3399_ch8.qxd //7 :37 Page Chapter 8 List ADT The ListNode Class Figure 8.3 compares the array implementation and the linked implementation. With the array implementation, these references are grouped together, occupying the contiguous memory location. Each reference is accessed by the index value of the array position. As detailed in Chapter 6, with the linked-list implementation, they are individually allocated. Since they do not occupy any contiguous memory locations, they must be linked to form a chain for us to be able access them. We define a class named ListNode to represent the pair of references. We often use the term link or pointer for the second reference that points to another list node. To distinguish the two different types of references, we use a blue arrow for the first reference and a red arrow for the link. Each node will be represented by a single ListNode object. The ListNode class has two data members, and the class is declared as follows (the generic parameter E is declared in the NPSLinkedList class): class ListNode { private E item; private ListNode next; public ListNode(E item) { this.item = item; this.next = null; 3 4 Array Implementation: :String :String :String :String "eel" Linked-List Implementation: :String :String :String :String "eel" Figure 8.3 The structural difference between the array and linked-list implementations.

wu3399_ch8.qxd //7 :37 Page 3 8.4 The Linked-List Implementation of the List ADT 3 The NPSLinkedList Class Similar to the NPSArrayList class, we need an int variable to keep track of the number of elements currently in the list. In addition, we use two references: one points to the first node, and the other points to the last node. The reference to the last node allows us to add a new node at the end of the list quickly. Without it, we have to traverse the links from the head to locate the last node. These data members are declared as private ListNode head; private ListNode tail; private int count; and initialized as head = null; tail = null; count = ; add in a constructor (the actual constructor calls the clear method, which resets the list as an empty list by executing the above three statements). Let s start with the first version. There are two cases we need to consider when adding an element at the end of the list. The first case involves adding an element to an empty list. Figure 8.4 illustrates this case. Both head and tail are null when the list is empty. When a node is added to an empty list, this node is both the first and last node of the list, so both head and tail are set to point to this newly added node. This is the end case. :NPSLinkedList tail head :NPSLinkedList tail head Note: newnode is a local variable and will be erased when the method terminates. newnode count count item Before After ListNode newnode = new ListNode(item); head = newnode; tail = newnode; count++; Figure 8.4 Adding an element at the end of an empty list.

wu3399_ch8.qxd //7 :37 Page 4 4 Chapter 8 List ADT Before :NPSLinkedList tail head count k :NPSLinkedList tail After newnode head count k+ item ListNode newnode = new ListNode(item); tail.next = newnode; tail = newnode; count++; Figure 8.5 The general case of adding an element at the end of a list. In the general case, where the list has one or more nodes, a newly added node is added at the end, so this new added node becomes the new tail node of the list. The pointer from the tail node before the addition is set to point to the new tail node after the addition. Figure 8.5 illustrates the general case. Here s the version add method: public void add(e item) { //creates a new ListNode ListNode newnode = new ListNode(item); if (isempty()) { head = tail = newnode;

wu3399_ch8.qxd //7 :37 Page 5 8.4 The Linked-List Implementation of the List ADT 5 else { tail.next = newnode; tail = newnode; count++; As was the case with the NPSArrayList class, we implemented the method explicitly to illustrate clearly the thinking process behind the operation, but we can actually implement it succinctly by calling the second version as follows: public void add(e item) { add(count, item); Now, let s see how we can implement the second version of the add method. Again, we have to handle the two cases separately. The end case occurs when the new node is added as the first element, that is, index ==.Inthis case we have to adjust the head to point to the newly added node and the link field of this new node to point to the node that was the first node before the addition. Figure 8.6 illustrates this case. In the general case, we must locate the position to insert the new node as the ith node. Unlike the array implementation, where we can locate an element at position i by simply using an indexed expression, in the case of linked implementation we must traverse the pointers in the linked fields. To insert a new node as the ith node in the list (the first node being the node), we need a pointer to the i-st node. Once we locate this node, the rest is a matter of adjusting two link fields. Figure 8.7 illustrates the general case. Here s the complete definition for the second version of the add method: public void add(int index, E item) throws IndexOutOfBoundsException { checkinsertposition(index); ListNode ptr = head; ListNode newnode = new ListNode(item); if (index == ) { //adding the new node as // the first node newnode.next = head; head = newnode; else { for (int i = ; i < index; i++) { ptr = ptr.next; newnode.next = ptr.next; ptr.next = newnode;

wu3399_ch8.qxd //7 :37 Page 6 6 Chapter 8 List ADT :NPSLinkedList tail head count k This is the th node. We mark its item X, so the before and after diagrams can be compared easily. Before X :NPSLinkedList tail After head count k+ newnode X item ListNode newnode = new ListNode(item); newnode.next = head; head = newnode; count++; Figure 8.6 The second version of add with index ==, i.e., adding an element as the first node in a list. //adjust tail if the new node added is //the last node in the list if (index == count) { tail = newnode; count++;

wu3399_ch8.qxd //7 :37 Page 7 8.4 The Linked-List Implementation of the List ADT 7 :NPSLinkedList This is the ith node before the insertion of the new node. tail Before head count k X ptr points to the (i-)st node. :NPSLinkedList ptr tail After head count k X newnode item This is the new ith node. ListNode newnode = new ListNode(item); newnode.next = ptr.next; ptr.next = newnode; count++; Figure 8.7 The general case of adding a new node as the ith node. Notice the last if statement in the method. If the newly added node is the last node after the insertion, then we must adjust the tail pointer. We know that the newly added node is the last node if its index is equal to count. If the test is true, then we set tail to point to the new node.

wu3399_ch8.qxd //7 :37 Page 8 8 Chapter 8 List ADT clear The clear method empties the list; that is, it resets the list as an empty list. Its implementation is straightforward. We reset head and tail to null and count to. By setting head to null, all the nodes in the list will eventually get garbage-collected. Here s the method: public void clear( ) { head = tail = null; count = ; contains The contains method is implemented by using the indexof method. If the indexof method returns a value other than NOT_FOUND (-), then the specified object is in the list, so the contains method returns true. If the indexof method returns NOT_FOUND, then the contains method returns false. public boolean contains(e item) { boolean result = true; int loc = indexof(item); if (loc == NOT_FOUND) { result = false; return result; get The get method for the linked implementation requires the traversing of link fields to locate the desired node. After checking that the passed index value is valid, the method traverses the pointers. The traversing is essentially the same as we did for the second version of the add method. The only difference is that we are setting the pointer ptr to point to the index node, not to the index-st node, as was the case with the add method. Here s the method: public E get(int index) throws IndexOutOfBoundsException { checkaccessposition(index); E item = null; This loop traverses the list by following the link field for index times. ListNode ptr = head; for (int i = ; i < index; i++) { ptr = ptr.next; item = ptr.item; return item;

wu3399_ch8.qxd //7 :37 Page 9 8.4 The Linked-List Implementation of the List ADT 9 indexof The indexof method traverses the pointers from head and stops when the first match is located. The counter loc is incremented every time the next node is visited. If the specified object is not in the list, then NOT_FOUND (-) is returned. public int indexof(e item) { int loc = ; ListNode ptr = head; while (loc < count &&!ptr.item.equals(item)) { loc++; ptr = ptr.next; if (loc == count) { loc = NOT_FOUND; return loc; Be careful that the order of operands in the while test is critical. We cannot write it as INVALID while (!ptr.item.equals(item) && loc < count) { isempty because doing so would result in a NullPointerException error in the case where the searched item is not found (i.e., when loc becomes equal to count, ptr is null). The isempty method is simple. We just check the value of the count variable. public boolean isempty( ) { return (count == ); remove For the first version of remove, wemust locate the i-st node. Once this node is located, all that is left to do is to adjust this node s next field. Unlike in the array implementation, no shifting is necessary. This is one advantage of the linked implementation. On the other hand, with the array implementation, there s no search is involved, while the linked implemention requires the traversal of links to locate the i-st node. Figure 8.8 illustrates the operation for the general case. There are end cases we need to watch out for: First, when the node we are removing is the last node in the list, we must adjust the tail pointer to point to the new last node after the removal. Second, when the node we are removing is the first node, then we must adjust the head pointer. If this first node is the only node in the list, then we must also adjust the tail pointer. If we are removing the

wu3399_ch8.qxd //7 :37 Page Chapter 8 List ADT :NPSLinkedList tail This is the ith node we re deleting. Before head count k X ptr points to the (i-)st node. :NPSLinkedList ptr tail After head count k X ptr.next = ptr.next.next; count--; Figure 8.8 The first version of the remove operation. Remove the ith node given the value i. only node in the list (both head and tail point to this node), the net result is that both head and tail become null. public E remove(int index) throws IndexOutOfBoundsException { checkaccessposition(index); ListNode deletenode; ListNode ptr = head; if (index == ) { //removing the first node deletenode = ptr; head = head.next;

wu3399_ch8.qxd //7 :37 Page 8.4 The Linked-List Implementation of the List ADT if (head == null) { //the first node is //the only node tail = null; else { for (int i = ; i < index; i++) { ptr = ptr.next; deletenode = ptr.next; ptr.next = deletenode.next; if (ptr.next == null) { //very last node was removed tail = ptr; //we have a new last node count--; return deletenode.item; The second version of remove requires a traversal to locate the node to be removed. If there are duplicates, then the first match is removed. If the passed item is not found, then nothing happens. To locate the desired node, we use two pointers: ptr and trail. The ptr will point to the node to be removed, and the trail will point to the node one before the ptr node. In other words, the following relationship holds between the two: trail.next == ptr As with the first version, we must watch out for the end cases of removing the first node, the last node, or the only node. Here s the second remove method: public boolean remove(e item) { boolean result = false; ListNode ptr = head; ListNode trail = null; while (ptr!= null &&!ptr.item.equals(item)) { trail = ptr; ptr = ptr.next; if (ptr!= null) { //found item if (trail == null) { //removing the first node head = head.next;

wu3399_ch8.qxd //7 :37 Page Chapter 8 List ADT if (head == null) { //the first node is //the only node tail = null; else { trail.next = ptr.next; if (trail.next == null) { //very last node was tail = trail; //removed, so set tail to //point to a new last node count--; result=true; return result; set After checking that the passed index value is valid, the set method traverses the list index times and sets the pointer ptr to the node to be modified. Once this node is located, its data field is set to refer to the passed item. public E set(int index, E item) { checkaccessposition(index); ListNode ptr = head; for (int i = ; i < index; i++) { ptr = ptr.next; E old = ptr.item; ptr.item = item; return old; size This method is easy (for a change). We simply return the value of the count variable. public int size( ) { return count;

wu3399_ch8.qxd //7 :37 Page 3 8.4 The Linked-List Implementation of the List ADT 3 We are now ready to list the complete NPSLinkedList class. In the source code listing, we do not show any javadoc comments, to keep the listing to a manageable size. The actual source code includes the full javadoc comments. NPSLinkedList package edu.nps.util; public class NPSLinkedList<E> implements NPSList<E> { public static final int NOT_FOUND = -; private ListNode head; private ListNode tail; private int count; public NPSLinkedList( ) { Constructor clear( ); public void add(e item) { add //creates a new ListNode ListNode newnode = new ListNode(item); if (count == ) { head = tail = newnode; else { tail.next = newnode; tail = newnode; count++; public void add(int index, E item) throws IndexOutOfBoundsException { checkinsertposition(index); add ListNode ptr = head; ListNode newnode = new ListNode(item); if (index == ) { //adding the new node as the first node newnode.next = head; head = newnode; else {

wu3399_ch8.qxd //7 :37 Page 4 4 Chapter 8 List ADT for (int i = ; i < index; i++) { ptr = ptr.next; newnode.next = ptr.next; ptr.next = newnode; //adjust tail if the new node added is //the last node in the list if (index == count) { tail = newnode; count++; public void clear( ) { clear head = tail = null; count = ; public boolean contains(e item) { contains boolean result = true; int loc = indexof(item); if (loc == NOT_FOUND) { result = false; return result; public E get(int index) throws IndexOutOfBoundsException { checkaccessposition(index); E item = null; get ListNode ptr = head; for (int i = ; i < index; i++) { ptr = ptr.next; item = ptr.item; return item; public int indexof(e item) { indexof int loc = ;

wu3399_ch8.qxd //7 :37 Page 5 8.4 The Linked-List Implementation of the List ADT 5 ListNode ptr = head; while (loc < count &&!ptr.item.equals(item)) { loc++; ptr = ptr.next; if (loc == count) { loc = NOT_FOUND; return loc; public boolean isempty( ) { isempty return (count == ); public E remove(int index) throws IndexOutOfBoundsException { checkaccessposition(index); ListNode deletenode; remove ListNode ptr = head; if (index == ) { //removing the first node deletenode = ptr; head = head.next; if (head == null) { //the first node is the only node tail = null; else { for (int i = ; i < index; i++) { ptr = ptr.next; deletenode = ptr.next; ptr.next = deletenode.next; if (ptr.next == null) { //very last node was removed tail = ptr; //we have a new last node count--; return deletenode.item;

wu3399_ch8.qxd //7 :37 Page 6 6 Chapter 8 List ADT public boolean remove(e item) { boolean result = false; remove ListNode ptr = head; ListNode trail = null; while (ptr!= null &&!ptr.item.equals(item)) { trail = ptr; ptr = ptr.next; if (ptr!= null) { //found item if (trail == null) { //removing the first node head = head.next; if (head == null) { //the first node is the only node tail = null; else { trail.next = ptr.next; if (trail.next == null) { //very last node was removed, so tail = trail; //set tail to point to a new last node count--; result = true; return result; public E set(int index, E item) { set checkacessposition(index); ListNode ptr = head; for (int i = ; i < index; i++) { ptr = ptr.next; E old = ptr.item; ptr.item = item; return old;

wu3399_ch8.qxd //7 :37 Page 7 8.4 The Linked-List Implementation of the List ADT 7 public int size( ) { return count; private void checkaccessposition(int index) { size checkaccessposition if (size() == ) { throw new IndexOutOfBoundsException( "Index " + index + " is invalid. List is empty."); else if (index < ) { throw new IndexOutOfBoundsException("Negative index of " + index + " is invalid"); else if (index > size()-) { throw new IndexOutOfBoundsException(index + " is larger than valid upper bound" + (size()-)); private void checkinsertposition(int index) { checkinsertposition if (index < ) { throw new IndexOutOfBoundsException( "Negative index of " + index + " is invalid"); else if (index > size()) { throw new IndexOutOfBoundsException(index + " is larger than valid upper bound" + size()); // Inner Class: ListNode class ListNode { ListNode private E item; private ListNode next; public ListNode(E item) { this.item = item; this.next = null;

wu3399_ch8.qxd //7 :37 Page 8 8 Chapter 8 List ADT end cases 8.5 The Linked Implementation with the Head Node In both versions of the add and remove methods of the linked implementation, we have to include a test to determine the special case of removing the first node because we need to treat the removal of the first node differently from the other general cases. The special cases are also called end cases or boundary cases. Consider the case of removal: If we are dealing with a large list, we do not expect the removal of the first node to happen frequently in ordinary applications. Yet, every time we remove a node we must test if it is the removal of the first node. It is not efficient to check every time for something that rarely occurs. Can we do something about it? Is there a way to eliminate this testing? The technique we can use to eliminate the testing of the end case is to insert one extra dummy node at the head of a list. By including this head node, one set of code can be used to handle both the end and general cases. Figure 8.9 shows the lists with the head node. An empty list :NPSLinkedList tail head This is the head node. It contains no information. count :NPSLinkedList tail A list with four items head count 4 :String :String :String :String "eel" Figure 8.9 Sample linked lists with the head node.

wu3399_ch8.qxd //7 :37 Page 9 8.5 The Linked Implementation with the Head Node 9 With the head node in a list, version remove can be written as follows: public E remove(int index) throws IndexOutOfBoundsException { checkaccessposition(index); ListNode deletenode; ListNode trail = head; for (int i = ; i <= index; i++) { trail = trail.next; deletenode = trail.next; trail.next = deletenode.next; if (deletenode.next == null) { //very last node was tail = trail; //removed so set tail //to the new last node count--; return deletenode.item; Compare this remove to the corresponding method of the NPSLinkedList class. The other remove method and the two versions of the add method can be improved in a similar manner. Here is the NPSLinkedListWithHeader class (the methods that remain the same as those in NPSLinkedList are not listed here). NPSLinkedListWithHeader package edu.nps.util; public class NPSLinkedListWithHeader<E> implements NPSList<E> { public static final int NOT_FOUND = -; private ListNode head; private ListNode tail; private int count; public NPSLinkedListWithHeader( ) { ListNode headnode = new ListNode(null); head = headnode; tail = headnode; count = ; Note: The methods that remain the same as those in NPSLinkedList are not listed here. Constructor

wu3399_ch8.qxd //7 :37 Page Chapter 8 List ADT public void add(e item) { //creates a new ListNode ListNode newnode = new ListNode(item); add tail.next = newnode; tail = newnode; count++; public void add(int index, E item) throws IndexOutOfBoundsException { checkinsertposition(index); ListNode ptr = head; add ListNode newnode = new ListNode(item); for (int i = ; i < index; i++) { ptr = ptr.next; newnode.next = ptr.next; ptr.next = newnode; //adjust tail if the new node added is //the last node in the list if (index == count) { tail = newnode; count++; public void clear( ) { clear head.next = null; //don't remove the dummy head node tail = head; count = ; public E get(int index) { get checkaccessposition(index); ListNode ptr = head.next; for (int i = ; i < index; i++) { ptr = ptr.next; return ptr.item;

wu3399_ch8.qxd //7 :37 Page 8.5 The Linked Implementation with the Head Node public int indexof(e item) { int loc = ; indexof ListNode ptr = head.next; while (loc < count &&!ptr.item.equals(item)) { loc++; ptr = ptr.next; if (loc == count) { loc = NOT_FOUND; return loc; public E remove(int index) throws IndexOutOfBoundsException { checkacessposition(index); ListNode deletenode; remove ListNode trail = head; for (int i = ; i <= index; i++) { trail = trail.next; deletenode = trail.next; trail.next = deletenode.next; if (deletenode.next == null) { //very last node was tail = trail; //removed so set tail //to the new last node count--; return deletenode.item; public boolean remove(e item) { remove boolean result = false; ListNode ptr = head.next; ListNode trail = head; while (ptr!= null &&!ptr.item.equals(item)) { trail = ptr; ptr = ptr.next;

wu3399_ch8.qxd //7 :37 Page Chapter 8 List ADT if (ptr!= null) { trail.next = ptr.next; if (trail.next == null) { //very last node was removed tail = trail; //we have a new last node Count--; result = true; return result; public E set(int index, E item) { set checkaccessposition(index); ListNode ptr = head.next; for (int i = ; i < index; i++) { ptr = ptr.next; E old = ptr.item; ptr.item = item; return old;... traversal 8.6 The Iterator Design Pattern One of the most common operations we perform on a data structure, including the linear list, is a traversal. Traversing a data structure means visiting, or accessing, every element in the data structure. For example, if a data structure contains Person objects and we want to find out their average age, we have to visit every Person object in the data structure to derive the sum of their ages and then divide the sum by the total number of elements. Traversing a complex data structure can be complicated because there could be many different ways to visit elements. For a simpler data structure, such as the linear list, however, traversal is straightforward. We visit the elements in sequence: visit the first element, the second element, and so forth. Here s a sample code for

wu3399_ch8.qxd //7 :37 Page 3 8.6 The Iterator Design Pattern 3 traversing Person objects in a list to compute their average: NPSList<Person> personlist; //Assume personlist is created and includes //Person objects; for simplicity we assume //the list includes at least one element double agesum, avgage; agesum = ; for (int i = ; i < personlist.size(); i++) { Person p = personlist.get(i); agesum += p.getage(); avgage = agesum / personlist.size(); iterator What would be the cost of such a traversal operation? It depends on the implementation. With the array implementation, the cost of accessing every element in the list is N, but with the linked-list implementation, the cost is (N N). Let s see why there is such an order-of-magnitude difference. The cost of the get method in the array implementation is the same regardless of the location of an element, because any element in an array can be accessed by applying the same address computation formula. How about the get method of the linked implementation? To access the ith element, we must traverse the links i times, starting from the head node, so the cost is i. Assuming that the cost of following a link and the cost of address computation are the same, we can derive the total cost for scanning as follows: N N for the i array implementation and N i (N N) for the linked implementation. i Since traversal is a frequently used operation, it is worth the effort to improve its performance. We would like to improve the performance of the linked-list implementation to the level of the array implementation, that is, from (N N) to N. We can do so by applying the technique known as the iterator design pattern. An iterator is a design pattern that supports a consistent way to access the elements stored in a data structure. We define an iterator as an ADT that supports two operations the first to prompt if there are more elements to visit and the second to retrieve the next element to visit. Here s the interface definition for the ADT: NPSIterator package edu.nps.util; interface NPSIterator<E> { public boolean hasnext( ); public E next( ) throws NPSNoSuchElementException;

wu3399_ch8.qxd //7 :37 Page 4 4 Chapter 8 List ADT The hasnext method returns true if there are more elements in the iterator. The next method returns the next object in the iterator if there is one. Otherwise, it throws an NPSNoSuchElementException. This exception class is patterned after the NoSuchElementException class in the java.util package. We avoid using classes and interfaces from the java.util package in our edu.nps.util package to make it selfcontained. We do not want to require client programmers to import the java.util package also when using the edu.nps.util package. We add a method, named iterator, to the NPSList interface that returns an iterator. With the iterator method, we can compute the average age of Person objects in a list as follows: NPSList<Person> personlist; //Assume personlist is created and includes //Person objects; for simplicity we assume //the list includes at least one element double agesum, avgage; agesum = ; NPSIterator itr = personlist.iterator(); while (itr.hasnext()) { Person p = itr.next(); agesum += p.getage(); avgage = agesum / personlist.size(); Let s first modify the NPSLinkedList class to include the iterator method. Notice that NPSIterator is an interface, so the iterator method must return an instance of a class that implements this interface. The best way to achieve this is to define an inner class that implements the NPSIterator interface inside the NPSLinkedList class. In this inner class, we keep a data member current that keeps track of the node whose item value we return when the next method is called. Every time the next method is called, we update the current pointer to the next node in the list. When the next method is called and the current points to the last node in the list, the updated current becomes null, and the next time the hasnext method is called, it returns false. Here s how we define the modified class: NPSLinkedList (final version) package edu.nps.util; public class NPSLinkedList<E> implements NPSList<E> {...

wu3399_ch8.qxd //7 :37 Page 5 8.6 The Iterator Design Pattern 5 public NPSIterator iterator( ) { return new MyIterator(head);... //-----Inner Class: MyIterator -------------// private class MyIterator implements NPSIterator<E> { private ListNode current; public MyIterator(ListNode node) { current = node; public boolean hasnext( ) { return current!= null; public E next( ) throws NPSNoSuchElementException { if (current == null) { throw new NPSNoSuchElementException("No more element"); Object item = current.item; current = current.next; return item; INVALID Notice that the type parameter is not specified for the inner class MyIterator. It is invalid to declare the inner class as private class MyIterator<E> implements NPSIterator<E> { Doing so would conflict with the type parameter of the outer class NPSLinkedList. With this invalid declaration, E in the inner class and E in the outer class would be viewed as referring to two different actual types. By not associating any type parameter to MyIterator, the generic type E in the inner and outer classes refers to the same actual type.

wu3399_ch8.qxd //7 :37 Page 6 6 Chapter 8 List ADT The NPSNoSuchElementException class is a very simple class. Here s the definition: NPSNoSuchElementException package edu.nps.util; public class NPSNoSuchElementException extends RuntimeException { public NPSNoSuchElementException( ) { this("requested element does not exist in the data structure"); public NPSNoSuchElementException(String message) { super(message); Now let s look at how we can implement the iterator method for the NPSArrayList class. We should realize that we are not gaining any performance improvement in doing this, because the cost of calling the get method N times, once for each node in the list, to scan the elements in a list is O(N). But defining the iterator method to the NPSArrayList class gives us a consistent and easy-to-use manner of traversing elements in all types of diverse data structures. We follow the same approach used in the iterator inner class of NPSLinkedList. This time, however, instead of the current pointer, we maintain an int data member current that keeps track of the index of the current node. We initialize current to. The hasnext method returns true if the value of current is less than or equal to the maximum possible index value, i.e., the size of the list minus. When the next method is called and the value of current is not less than the size of the list, it throws an exception. Otherwise, the method returns the current element and increments current by so it will point to the next element. The modified NPSArrayList is defined as follows: NPSArrayList (final version) package edu.nps.util; public class NPSArrayList<E> implements NPSList<E> {... public NPSIterator iterator( ) { return new MyIterator();

wu3399_ch8.qxd //7 :37 Page 7 8.7 Sample Development 7 ////---------- Inner Class : MyIterator -------------//// private class MyIterator implements NPSIterator<E> { private int current; public MyIterator( ) { current = ; public boolean hasnext( ) { if (current < size()-) { return true; else { return false; public E next( ) throws NPSNoSuchElementException { if (current >= size()) { throw new NPSNoSuchElementException(); else { int idx = current; //these three statements can be written current++; //succinctly in a single statement as return element[idx]; //return element[current++] Sample Development 8.7 Sample Development Fortune Cookies Let s write a simple application that illustrates the use of a list. The program will display a fortune cookie, a short text message, when requested by the user. Since each fortune cookie is a string, we maintain a database of fortune cookies using a list ADT. Problem Statement Write a program that displays a fortune cookie (text message) every time the user wishes it. Repeatedly prompt the user if he or she wishes to read another fortune cookie. If the reply is yes, display it. If the reply is no, terminate the program. Assume there is a text file named fortune.txt that contains text messages. Each line of text represents a single fortune cookie.