ch02 List
ch02 List
Section 2.1
List Interface and ArrayList Class (cont.)
Java provides a List interface as part of its API java.util
Classes that implement the List interface provide the functionality of an indexed
data structure and offer many more operations
A sample of the operations:
Obtain an element at a specified position
Replace an element at a specified position
Find a specified target value
Add an element at either end
Remove an element from either end
Insert or remove an element at any position
Traverse the list structure without managing a subscript
All classes introduced in this chapter support these operations, but they do not
support them with the same degree of efficiency
java.util.List Interface and its Implementers
List Interface and ArrayList Class
Unlike the Array data structure, classes that implement the List
interface cannot store primitive types
Classes must store values as objects
This requires you to wrap primitive types, such an int and
double in object wrappers, in these cases, Integer and Double
8
ArrayList Class
Removing an element:
myList.remove(1);
myList.set(2, "Sneezy");
ArrayList Class (cont.)
myList.indexOf("Jumpy");
The statement
List<String> myList = new ArrayList<String>();
uses a language feature called generic collections or generics
The statement creates a List of String; only references of type
String can be stored in the list
String in this statement is called a type parameter
The type parameter sets the data type of all objects stored in a
collection
Generic Collections (cont.)
The general declaration for generic collection is
CollectionClassName<E> variable =
new CollectionClassName<E>();
The <E> indicates a type parameter
Adding a noncompatible type to a generic collection will generate an
error during compile time
However, primitive types will be autoboxed:
ArrayList<Integer> myList = new ArrayList<Integer>();
myList.add(new Integer(3)); // ok
myList.add(3); // also ok! 3 is automatically wrapped
in an Integer object
myList.add(new String("Hello")); // generates a type
incompatability error
Why Use Generic Collections?
Section 2.2
Example Application of ArrayList
ArrayList<Integer> someInts = new ArrayList<Integer>();
int[] nums = {5, 7, 2, 15};
for (int i = 0; i < nums.length; i++) {
someInts.add(nums[i]);
}
if (index != -1)
dE = theDirectory.get(index);
else
dE = null;
Implementation of an ArrayList Class
Section 2.3
Implementing an ArrayList Class
To insert into the middle of the array, the values at the insertion
point are shifted over to make room, beginning at the end of the
array and proceeding in the indicated order
Implementing ArrayList.add(index,E)
public void add (int index, E anEntry) {
// check bounds
if (index < 0 || index > size) {
throw new ArrayIndexOutOfBoundsException(index);
}
// Make sure there is room
if (size >= capacity) {
reallocate();
}
// shift data
for (int i = size; i > index; i--) {
theData[i] = theData[i-1];
}
// insert item
theData[index] = anEntry;
size++;
}
set and get Methods
public E get (int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException(index);
}
return theData[index];
}
E returnValue = theData[index];
size--;
return returnValue;
}
reallocate Method
Create a new array that is twice the size of the current array and
then copy the contents of the new array
private void reallocate () {
capacity *= 2;
theData = Arrays.copyOf(theData, capacity);
}
reallocate Method (cont.)
private void reallocate () {
capacity *= 2;
theData = Arrays.copyOf(theData, capacity);
}
and so on . . .
Big-O Notation (cont.)
You must also examine the number of times a loop is executed
for(i=1; i < x.length; i *= 2) {
// Do something with x[i]
}
The loop body will execute k-1 times, with i having the following values:
1, 2, 4, 8, 16, . . ., 2k
until 2k is greater than x.length
Since 2k-1 = x.length < 2k and log22k is k, we know that k-1 = log2(x.length)
<k
Thus, we say the loop is O(log n) (in analyzing algorithms, we use
logarithms to the base 2)
Logarithmic functions grow slowly as the number of data items n increases
Formal Definition of Big-O
Consider the following program structure:
In terms of T(n),
T(n) = O(f(n))
There exist
two constants, n0 and c, greater than zero, and
a function, f(n),
T(n) = 3(n – 1) + 3 (n – 2) + … + 3
Factoring out the 3,
3(n – 1 + n – 2 + n – 3 + … + 1)
1 + 2 + … + n – 1 = (n x (n-1))/2
Big-O Example 2 (cont.)
tom.next = dick;
dick.next = harry;
harry.next = sam;
A Single-Linked List Class
Node<String>
next =
data = "Ann"
The element
added to the list
Implementing SLList.addFirst(E item) (cont.)
private void addFirst (E item) {
Node<E> temp = new Node<E>(item, head);
head = temp;
size++;
}
Node<String>
next =
data = "Ann"
The element
added to the list
Implementing addAfter(Node<E> node, E item) (cont.)
private void addAfter (Node<E> node, E item) {
Node<E> temp = new Node<E>(item, node.next);
node.next = temp;
We declare this method
size++; private since it should not be
} called from outside the class.
Later we will see how this
method is used to implement
or, more simply ... the public add methods.
temp
Node<String>
The Node
parameter next =
data = "Ann"
Implementing removeAfter(Node<E> node) (cont.)
private E removeAfter (Node<E> node) {
Node<E> temp = node.next;
if (temp != null) {
node.next = temp.next;
size--;
return temp.data;
} else {
return null;
}
}
Implementing SLList.removeFirst()
SLList<String> Node<String>
head = next =
data = "Dick"
Node<String>
next =
temp data = "Tom"
Implementing SLList.removeFirst() (cont.)
private E removeFirst () {
Node<E> temp = head;
if (head != null) {
head = head.next;
}
if (temp != null) {
size--;
return temp.data
} else {
return null;
}
}
Traversing a Single-Linked List
Do something
with nodeRef
Node<String>
nodeRef
next = null
data = "Ann"
Traversing a Single-Linked List (cont.)
toString()can be implemented with a traversal:
public String toString() {
Node<String> nodeRef = head;
StringBuilder result = new StringBuilder();
while (nodeRef != null) {
result.append(nodeRef.data);
if (nodeRef.next != null) {
result.append(" ==> ");
}
nodeRef = nodeRef.next;
}
return result.toString();
}
SLList.getNode(int)
sharon
Node<E> sharon = new Node<E>("Sharon");
sharon.next = sam;
sharon.prev = sam.prev; Node
sam.prev.next = sharon;
sam.prev = sharon next =
= prev
data = "Sharon"
Removing from a Double-Linked List
harry
Node Node
next = next =
= prev = prev
data = "Dick" data = "Sharon"
Node
next =
harry.prev.next = harry.next = prev
harry.next.prev = harry.prev data = "Harry"
A Double-Linked List Class
Section 2.7
The LinkedList Class
The Iterator
To remove all elements from a list of type Integer that are divisible by
a particular value:
Iterator limitations
Traverses List only in the forward direction
Provides a remove method, but no add method
You must advance the Iterator using your own loop if you do not start
from the beginning of the list
ListIterator extends Iterator, overcoming these limitations
ListIterator Interface (cont.)
ListIterator:
nextIndex()returns the index of item to be returned by next()
previousIndex() returns the index of item to be returned by
previous()
LinkedList has method listIterator(int index)
Returns a ListIterator positioned so next()will return the item at
position index
Conversion Between ListIterator and an Index
(cont.)
The listIterator (int index) method creates a new
ListIterator that starts at the beginning, and walks down the
list to the desired position – generally an O(n) operation
Enhanced for Statement
count = 0;
for (String nextStr : myList) {
if (target.equals(nextStr)) {
count++;
}
}
Enhanced for Statement (cont.)
sum = 0;
for (int nextInt : myList) {
sum += nextInt;
}
Enhanced for Statement (cont.)
The enhanced for statement also can be used with arrays, in this
case, chars or type char[]
. . .
Add Method
1. Obtain a reference, nodeRef, to the node at /** Add an item at the specified
index.
position index @param index The index at
which the object is
2. Insert a new Node containing obj before the node to be inserted
referenced by nodeRef @param obj The object to be
inserted
To use a ListIterator object to implement add:
@throws
1. Obtain an iterator that is positioned just before IndexOutOfBoundsException
if the index is out
the Node at position index of range
(i < 0 || i > size())
2. Insert a new Node containing obj before the Node */
currently referenced by this iterator public void add(int index, E obj) {
It is not necessary to listIterator(index).add(obj);
declare a local }
ListIterator; the method
call listIterator returns
an anonymous
listIterator object
Get Method
public E getFirst() {
return head.data;
}
public E getLast() {
return tail.data;
}
Implementing the ListIterator Interface
public E next() {
KWListIter if (!hasNext()) {
throw new NoSuchElementException();
}
nextItem lastItemReturned = nextItem;
lastItemReturned nextItem = nextItem.next;
index 1 2 index++;
return lastItemReturned.data;
}
Previous Methods
public boolean hasPrevious() {
return (nextItem == null && size != 0)
|| nextItem.prev != null;
}
public E previous() {
if (!hasPrevious()) {
throw new NoSuchElementException();
}
if (nextItem == null) { // Iterator past the last element
nextItem = tail;
}
else {
nextItem = nextItem.prev;
}
lastItemReturned = nextItem;
index--;
return lastItemReturned.data;
}
ListIterator Interface (cont.)
The Add Method
(after insertion)
if (head == null) {
head = new Node<E>(obj);
tail = head;
}
...
size++
Adding to the Head of the List
KWListIter
nextItem =
lastItemReturned = null
index = 0 1
Node Node Node
nextItem = null
lastItemReturned = null
index = 2 3 Node Node Node
head = null
tail = null
size = 3 4 if (nextItem == null) {
Node<E> newNode = new Node<E>(obj);
tail.next = newNode; Node
newNode.prev = tail;
tail = newNode next = null
} null = prev
... newNode
data = "Bob"
size++;
index++;
Adding to the Middle of the List
KWListIter
nextItem = null
lastItemReturned = null
index = 1 2 Node Node Node
head = null
tail = null
size = 3 4
else {
Node<E> newNode = new Node<E>(obj); Node
newNode.prev = nextItem.prev;
nextItem.prev.next = newNode; next = null
newNode.next = nextItem; null = prev
nextItem.prev = newNode; data = "Bob"
}
...
size++;
index++; newNode
Inner Classes: Static and Nonstatic
but including
add(E)
remove(Object)
Collections
grow as needed
hold references to objects
iterator()
Extend AbstractList<E>
You need to implement only:
add(int, E)
get(int)
remove(int)
set(int, E)
size()
Black-box testing:
tests the item (method, class, or program) based on its interfaces and
functional requirements
is also called closed-box or functional testing
White-box testing:
tests the item (method, class, or program) with knowledge of its
internal structure
is also called glass-box, open-box, or coverage testing
if (TESTING) {
// Code for output statements
}
Remove these features when you are satisfied with the testing results
You can define different boolean flags for different tests
Developing the Test Data
Example
for (int i = 0; i < x.length; i++) {
if (x[i] == target)
return i;
}
Test the boundary conditions (for white-box and black-box testing)
when target is:
first element (x[0] == target is true)
last element (x[length-1] == target is true)
not in array (x[i] == target is always false)
present multiple times (x[i] == target for more than one value of i)
Testing Boundary Conditions (cont.)
Stubs can
print out value of inputs
assign predictable values to outputs
To test an OrderedList,
store a collection of randomly generated integers in an OrderedList
test insertion at beginning of list: insert a negative integer
test insertion at end of list: insert an integer larger than any integer in
the list
create an iterator and iterate through the list, displaying an error if any
element is smaller than the previous element
remove the first element, the last element, and a middle element, then
traverse to show that order is maintained
Testing OrderedList (cont.)
Class TestOrderedList
import java.util.*;