public class List<E extends Comparable<E>> {
public void add(E item)
class SortedList<E extends Comparable<E>> { private Node<E> head; private int size; public void add(E item) { Node<E> curr = head; Node<E> beforeCurr = null; //advance curr until null or pointing to first node >= item while (curr != null && curr.getData().compareTo(item) < 0) { beforeCurr = curr; curr = curr.getNext(); } if (beforeCurr == null) { //or: if (curr == this.head) { //adding at head of list this.head = new Node<E>(item, this.head); }else { beforeCurr.setNext(new Node<E>(item, curr)); } this.size++; } //...other methods... }
Node<E> before = this.getNode(index - 1); //if sentinel == -1 Node<E> toAdd = new Node<E>(item, before.getNext()); before.setNext(toAdd); this.size++;
public class DLNode<E> { private E data; private DLNode<E> next; private DLNode<E> prev; public DLNode(DLNode<E> prev, E data, DLNode<E> next) { this.data = data; this.prev = prev; this.next = next; } public DLNode(E data) { this(data, null); } public E getData() { return data; } public void setData(E data) { this.data = data; } public DLNode<E> getNext() { return next; } public void setNext(DLNode<E> next) { this.next = next; } public DLNode<E> getPrevious() { return prev; } public void setPrevious(DLNode<E> prev) { this.prev = prev; } }
Alternatively: could have extended Node to just add previous details.
public class DLNode<E> extends Node<E> { private DLNode<E> prev; public DLNode(DLNode<E> prev, E data, DLNode<E> next) { super(data, next); this.prev = prev; } public DLNode(E data) { this(null, data, null); } public DLNode<E> getPrevious() { return prev; } public void setPrevious(DLNode<E> prev) { this.prev = prev; } }
This can be a little problematic to use in practice, though, since getNext() returns a Node while getPrevious() returns a DLNode. This means you can't do something like node.getNext().getPrevious() without casting.
public String toString() { String str = ""; DLNode<E> curr = this.sentinel.getNext(); while (curr != this.sentinel) { str += curr.getData() + " "; //crude toString formatting curr = curr.getNext(); } return str; }
List<String> list = new List<String>(); //...add some values... for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); }
Basically an object that moves along the list
public class List<E> { //...current contents... public class LinkedListIterator implements java.util.Iterator<E> { //Note: did not redeclare <E> Node<E> next; //Node of item to return on next call to next() public LinkedListIterator() { this.next = head; //refers's to List's head. Explicit: List.this.head } public boolean hasNext() { return next != null; } public E next() { if (next == null) { throw new java.util.NoSuchElementException(); }else { E item = next.getData(); next = next.getNext(); return item; } } public void remove() { //optional: not implemented here throw new UnsupportedOperationException(); } } }//end of List
class List<E> implements Iterable<E> { //...current contents... public java.util.Iterator<E> iterator() { return new LinkedListIterator(); //or: new List<E>.LinkedListIterator(); } //...nested LinkedListIterator class here... }
List<Integer> list = new List<Integer>(); for (int i = 1; i < 10; i++) { list.add(i - 1, i); } //iterator for-each loop (thanks to List implementing Iterable) for (int item : list) { System.out.print(item + " "); } System.out.println(); //basically equivalent using iterator directly int item; for (java.util.Iterator<Integer> iter = list.iterator(); iter.hasNext(); ) { item = iter.next(); System.out.print(item + " "); } System.out.println();
public class LinkedListIterator implements java.util.Iterator<E> { Node<E> next; //Node of item to return on next call to next() Node<E> last; //Node of item returned by last call to next() Node<E> beforeLast; //Node before last, needed for remove() public LinkedListIterator() { this.next = head; //refers's to List's head. Explicit: List.this.head this.last = null; this.beforeLast = null; } public boolean hasNext() { return next != null; } public E next() { if (next == null) { throw new java.util.NoSuchElementException(); }else { E item = next.getData(); //advance along list if (last != null) { beforeLast = last; } last = next; next = next.getNext(); return item; } } public void remove() { if (this.last == null) { //next() not called yet or already removed since call throw new IllegalStateException(); }else { if (beforeLast == null) { //haven't returned second item of list yet, so removing first head = next; }else { beforeLast.setNext(next); } last = null; //so we know we removed since last call to next() } } }
Wouldn't need beforeLast
if we had a doubly-linked list.