Many of these can be implemented based on core 4 methods, tho
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++; }
Instance variables and constructor
public class List<E> { private Node<E> head; private int size; public List() { this.head = null; this.size = 0; } //...
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; } }
/**
* 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;
}
/**
* 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 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;
}
/**
* Returns the number of items currently stored in this list.
*/
public int size() {
return 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();
}
/**
* 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();
}
}
The fact that insertion/removal operation is O(1) is important for iterators (coming next week).
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; } }