Most 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;
}
}