08a: List ADT

ICS211, Spring 2013
Dr. Zach

(switch view)

Status check

List ADT

List ADT (optional)

Many of these can be implemented based on core 4 methods, tho

List Use

Array-based List

Just a taste/reminder:

//instance variables
private E[] items;
private int free;  //first empty spot in array

public void add(int index, E item) {
  if (index < 0 || index > this.free) {
    throw new IndexOutOfBoundsException("Can't add beyond the range of the list.");
  }
  if (this.free == this.items.length) {
    //need to expand array first
    this.items = java.util.Arrays.copyOf(this.items, this.items.length * 2);
  }
  //shift everything to right until we get to insertion index
  for (int i = this.free; i > index; i--) {
    this.items[i] = this.items[i - 1];
  }
  this.items[index] = item;
  this.free++;
}

Array-based List: Big-Os

Node-based List Implementation: Variables

Instance variables and constructor

public class List<E> {

  private Node<E> head;
  private int size;

  public List() {
    this.head = null;
    this.size = 0;
  }
  
  //...

Reminder: Node class

public class Node<E> {

  private E data;
  private Node<E> next;

  public Node(E data, Node<E> next) {
    this.data = data;
    this.next = next;
  }

  public Node(E data) {
    this(data, null);
  }

  public E getData() {
    return data;
  }

  public void setData(E data) {
    this.data = data;
  }

  public Node<E> getNext() {
    return next;
  }

  public void setNext(Node<E> next) {
    this.next = next;
  }
}

Node-based List Implementation: getNode

  /**
   * Returns the node at the given 0-based index in this list.
   * Throws IndexOutOfBoundsException if the index is outside the list.
   */
  private Node<E> getNode(int index) {
    if (index < 0 || index >= this.size) {
      //always thrown if list is empty
      throw new IndexOutOfBoundsException("index: " + index +
          "; size: " + this.size);
    }

    //start at head and move to next node index times.
    Node<E> curr = this.head;
    for (int i = 0; i < index; i++) {
      curr = curr.getNext();
    }
    return curr;
  }

Node-based List Implementation: add

  /**
   * Inserts the item at the given index, pushing any exiting items to right.
   * If index == size(), adds item to the end of the list.
   * Throws IndexOutOfBoundsException if the index is outside of list range.
   */
  public void add(int index, E item) {
    if (index == 0) {
      //special case: adding to head of list
      this.head = new Node<E>(item, this.head);
      this.size++;
    }else {
      Node<E> before = this.getNode(index - 1); //also checks index for us
      Node<E> toAdd = new Node<E>(item, before.getNext());
      before.setNext(toAdd);
      this.size++;
    }
  }

Node-based List Implementation: toString

  /**
   * Returns a String representation of this lists contents using the
   * format: [item1, items2, item3]
   */
  @Override public String toString() {
    String str = "[";
    Node<E> curr = this.head;
    while (curr != null) {
      str += curr.getData();  //implicitly calls toString on data item
      curr = curr.getNext();
      if (curr != null) {
        str += ", ";
      }
    }
    str += "]";
    return str;
  }

Node-based List Implementation: size

  /**
   * Returns the number of items currently stored in this list.
   */
  public int size() {
    return this.size;
  }

Node-based List Implementation: get

  /**
   * Returns the item at the given 0-based index in this list.
   * Throws IndexOutOfBoundsException if the index is outside of list range.
   */
   public E get(int index) {
     return this.getNode(index).getData();
   } 

Node-based List Implementation: remove

  /**
   * Removes and returns the item at the given 0-based index in this list.
   * Throws IndexOutOfBoundsException if the index is outside of list range.
   */
   public E remove(int index) {
     if (index == 0 && this.head != null) {
       //special case: removing first node
       E item = this.head.getData();
       this.head = this.head.getNext();
       this.size--;
       return item;
     }else {
       Node<E> toRemove = this.getNode(index);  //confirm that index is valid
       Node<E> before = this.getNode(index - 1);
       before.setNext(toRemove.getNext());
       this.size--;
       return toRemove.getData();
     }
   }

Node-based List: Big-Os

The fact that insertion/removal operation is O(1) is important for iterators (coming next week).

Complete singly-linked list implementation

public class List<E> {

  private Node<E> head;
  private int size;

  /**
   * Constructs a new empty list.
   */
  public List() {
    this.head = null;
    this.size = 0;
  }

  /**
   * Inserts the item at the given index, pushing any exiting items to right.
   * If index == size(), adds item to the end of the list.
   * Throws IndexOutOfBoundsException if the index is outside of list range.
   */
  public void add(int index, E item) {
    if (index == 0) {
      //special case: adding to head of list
      this.head = new Node<E>(item, this.head);
      this.size++;
    }else {
      Node<E> before = this.getNode(index - 1); //also checks index for us
      Node<E> toAdd = new Node<E>(item, before.getNext());
      before.setNext(toAdd);
      this.size++;
    }
  }
  
  /**
   * Returns the item at the given 0-based index in this list.
   * Throws IndexOutOfBoundsException if the index is outside of list range.
   */
   public E get(int index) {
     return this.getNode(index).getData();
   }

  /**
   * Returns the node at the given 0-based index in this list.
   * Throws IndexOutOfBoundsException if the index is outside the list.
   */
  private Node<E> getNode(int index) {
    if (index < 0 || index >= this.size) {
      //always thrown if list is empty
      throw new IndexOutOfBoundsException("index: " + index +
          "; size: " + this.size);
    }

    //start at head and move to next node index times.
    Node<E> curr = this.head;
    for (int i = 0; i < index; i++) {
      curr = curr.getNext();
    }
    return curr;
  }
  
  /**
   * Removes and returns the item at the given 0-based index in this list.
   * Throws IndexOutOfBoundsException if the index is outside of list range.
   */
   public E remove(int index) {
     if (index == 0 && this.head != null) {
       //special case: removing first node
       E item = this.head.getData();
       this.head = this.head.getNext();
       this.size--;
       return item;
     }else {
       Node<E> toRemove = this.getNode(index);  //confirm that index is valid
       Node<E> before = this.getNode(index - 1);
       before.setNext(toRemove.getNext());
       this.size--;
       return toRemove.getData();
     }
   }

  /**
   * Returns the number of items currently stored in this list.
   */
  public int size() {
    return this.size;
  }
  
  /**
   * Returns a String representation of this lists contents using the
   * format: [item1, items2, item3]
   */
  @Override public String toString() {
    String str = "[";
    Node<E> curr = this.head;
    while (curr != null) {
      str += curr.getData();  //implicitly calls toString on data item
      curr = curr.getNext();
      if (curr != null) {
        str += ", ";
      }
    }
    str += "]";
    return str;
  }
}

For next time...