08a: List ADT variants

ICS211, Fall 2012
Dr. Zach

(switch view)

Status check

Last time

List ADT variant: Sorted list

List variant: Sentinel node

List variant: Doubly-linked nodes

public class DLNode<E> extends Node<E> {

  private E data;
  private DLNode<E> next;
  private DLNode<E> prev;

  public DLNode(E data, DLNode<E> next) {
    this.data = data;
    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.

Doubly-linked List

List variant: tail pointer

List variant: Circular list

List variant: Array-based linked list

Iterators

Why we need them

  List<String> list = new List<String>();
  //...add some values...
  for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));  
  }

java.util.Iterator<E> interface

Basically an object that moves along the list

Our Iterator

A basic Iterator

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

How to build a new iterator?

Iterable List

class List<E> implements Iterable<E> {
  //...current contents...

  
  public java.util.Iterator<E> iterator() {
    return new LinkedListIterator();  //or: new List<E>.LinkedListIterator();
  }
}

Iterator and Iterable use

  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();

An Iterator with remove() implemented

  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()
      }
    }
  }

Could use only next and last (or similar) if we had a doubly-linked list.

For next time