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