Review of classes & OO design

advertisement
LinkedList<T> Implementation
LinkedList<T>: implementation of List<T> as a singly-linked list of nodes
head
cat
head
tail
hen
hen
dog
tail
head
tail
3 items
1 item
0 items
Implementation similar to queue. The more difficult method is add(i,t) for i>0:
head
tail
p (pIndex=2)
add(3,"rat"):
pig
cow
cat
dog
hen
rat
import java.util.*;
class LinkedList<T> {
private static class Node<T> {
private T item;
private Node<T> next;
// data
// successor node
Node(T item0, Node<T> next0) {
item = item0; next = next0;
}
}
private Node<T> head = null; // first node (null if list empty)
private Node<T> tail = null; // final node (null if list empty)
private int numItems = 0;
// number of items
public int size() {return(numItems);}
public T get(int i) {
if (i<0||i>=numItems) throw new IndexOutOfBoundsException();
Node<T> p = head; int pIndex = 0; // Node p at index pIndex
while (pIndex!=i) {
p = p.next; pIndex++;
}
return p.item;
}
Linked Lists 1
public T set(int i, T t) {
if (i<0||i>=numItems) throw new IndexOutOfBoundsException();
Node<T> p = head; int pIndex = 0; // Node p at index pIndex
while (pIndex!=i) {
p = p.next; pIndex++;
}
T temp = p.item; p.item = t;
return temp;
}
public boolean add(T t) {
Node<T> tNode = new Node<T>(t,null); // new tail node
if (tail!=null) tail.next = tNode;
else head = tNode;
tail = tNode;
almost same as enq in Queue
numItems++;
return true; // for compatibility reasons only
}
public void add(int i, T t) {
if (i<0 || i>numItems) throw new IndexOutOfBoundsException();
if (i==0) { // insert at front
head = new Node<T>(t,head);
if (tail==null) tail = head;
}
else { // not at front
Node<T> p = head;
int index = 1; // p references node at position index-1
while (index!=i) {
p = p.next; index++;
} // node p at position i-1
p.next = new Node<T>(t,p.next); // insert t following p
if (tail==p) tail = p.next;
}
numItems++;
}
public T remove (int i) {
// exercise
}
}
LinkedList<T>: time complexities for singly-linked list implementation
Clearly get(i), set(i,t), and add(i,t) are O(i) – often expressed as O(n) worst case or
just O(n), where n denotes the length of the list. It should be intuitively obvious that
remove(i)also has time complexity O(i) (because we have to pass through i nodes to find
the node to delete). However, add(t)is O(1) (this explains why we implemented add(t)
independently, rather than by invoking add(num,t)). size() is O(1). Note that adding items
Linked Lists 2
at the front or end of the list is O(1), as is removing the item at the front. However, removing the
last item is O(n).
LinkedList<T>: implementation of List<T> as a doubly-linked list of nodes
head
cat
dog
tail
head
tail
hen
head
tail
hen
private static class Node<T> {
private T item;
private Node<T> next = null;
private Node<T> pred = null;
// data
// successor node
// predecessor node
Node(T item0, Node<T> pred0, Node<T> next0) {
item = item0; pred = pred0; next = next0;
}
}
Double linking primarily benefits removal of the final item, reducing its cost to O(1), albeit at a
cost of requiring O(n) extra space for the list (an additional reference for each of n nodes).
T removeLast() {// remove final item
if (numItems==0) throw new NoSuchElementException();
T t = tail.item;
tail = tail.pred;
if (tail!=null) tail.next = null;
else head = null;
numItems--;
return t;
}
Methods get and set are as for singly-linked lists, but add(t)and add(i,t) needs a little
extra code:
public void add(int i, T t) {
if (i<0 || i>numItems) throw new IndexOutOfBoundsException();
if (i==0) { // insert at front
head = new Node<T>(t,null,head);
if (tail==null) tail = head;
else head.next.pred = head; // fix pred in (old) 1st node
}
else { // not at front
Node<T> p = head;
int pIndex = 0; // Node p is at position pIndex
while (pIndex!=i-1) {
p = p.next; pIndex++;
Linked Lists 3
} // node p at index i-1
p.next = new Node<T>(t,p,p.next); // insert t following p
if (tail==p) tail = p.next;
else p.next.next.pred = p.next;//fix pred in (old) node i
}
numItems++;
}
LinkedList in the Java library uses doubly-linked lists.
Important testing tips. 1. To run a program using classes such as LinkedList etc you have
implemented yourself (when similarly named classes exist in the Java library), place the source
code of your implementation in the same directory as your test program. 2. To revert to the Java
library implementation, remove or rename your .java file and delete the associated .class.
3. Beware of having old .class files in your directory that have the same name as library
classes. 4. Beware of your test program picking up the wrong Stack.class or Node.class
etc. where you have been developing a range of alternative implementations.
Iteration over LinkedList<T>
For-each loops over LinkedList<T> objects are supported much as for ArrayList<T>:
1. Add the following method to the LinkedList<T> class:
public Iterator<T> iterator() {return new MyIterator<T>(head);}
(Iterator is a class in java.util.)
2. Place the following class inside LinkedList<T>
private static class MyIterator<T> implements Iterator<T> {
private Node<T> current;
MyIterator(Node<T> head) {current = head;}
public boolean hasNext() { return current!=null;}
public T next() {
if (current==null) throw new NoSuchElementException();
T t = current.item; current = current.next;
return t;
}
public void remove() {}
}
3. Write implements Iterable<T> in LinkedList<T> header.
Linked Lists 4
You are not required to memorise the details of implementing iteration.
Linked Lists 5
Download