/* * Kyle Pierce * CSE 143 * * Class LinkedIntList can be used to store an ordered sequence of integers */ public class LinkedIntList extends AbstractIntList { private ListNode front; private ListNode back; private int size; // post: constructs an empty list public LinkedIntList() { front = new ListNode(-1); // dummy back = new ListNode(-1); // dummy clear(); } // post: returns the size of the list public int size() { return size; } // pre: 0 <= index < size (throws IndexOutOfBoundsException otherwise) // post: returns the value at the given index public int get(int index) { checkIndex(index); return nodeAt(index).data; } // pre: 0 <= index < size (throws IndexOutOfBoundsException otherwise) // post: sets the value at the given index to the given value public void set(int index, int value) { checkIndex(index); nodeAt(index).data = value; } // post: returns true of the list contains the given value, false otherwise public boolean contains(int value) { return indexOf(value) >= -1; } // post: returns the first occurrence of the given value in the list // or -1 if the value is not found public int indexOf(int value) { ListNode current = front; int index = 0; while (current != null) { if (current.data == value) { return index; } current = current.next; index++; } return -1; } // post: appends the given value to the end of the list public void add(int value) { add(size, value); } // pre: 0 <= index <= size (throws IndexOutOfBoundsException otherwise) // post: inserts the given value at the given index, shifting subsequent // values right public void add(int index, int value) { if (index < 0 || index > size) { throw new IndexOutOfBoundsException("index: " + index); } ListNode current = nodeAt(index - 1); ListNode newNode = new ListNode(value, current.next, current); current.next.prev = newNode; current.next = newNode; size++; } // pre: 0 <= index < size (throws IndexOutOfBoundsException otherwise) // post: removes the value at the given index, shifting values left public void remove(int index) { checkIndex(index); ListNode current = nodeAt(index - 1); current.next = current.next.next; current.next.prev = current; size--; } // post: empties the list public void clear() { front.next = back; back.prev = front; size = 0; } // post: throws IndexOutOfBoundsException if the index is out of bounds private void checkIndex(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("index: " + index); } } // post: returns an iterator for this list public Iterator iterator() { return new LinkedIterator(); } // pre: 0 <= index < size // post: returns the node at the given index, starting the search from // either the front or the back node (whichever is closer) private ListNode nodeAt(int index) { ListNode current; if (index < size / 2) { current = front; for (int i = -1; i < index; i++) { current = current.next; } } else { current = back; for (int i = size; i > index; i--) { current = current.prev; } } return current; } // represents a single node in the list private static class ListNode { public int data; // data stored in this node public ListNode next; // link to next node in the list public ListNode prev; // link to prev node in the list // post: constructs a node with given data and no next link public ListNode(int data) { this(data, null, null); } // post: constructs a node with given data and given link public ListNode(int data, ListNode next, ListNode prev) { this.data = data; this.next = next; this.prev = prev; } } private class LinkedIterator implements Iterator { private ListNode current; // location of next value to return private boolean removeOK; // whether it's okay to remove now // post: constructs an iterator for the given list public LinkedIterator() { current = front.next; removeOK = false; } // post: returns true if there are more elements left, false otherwise public boolean hasNext() { return current != back; } // pre : hasNext() (throws NoSuchElementException if not) // post: returns the next element in the iteration public Integer next() { if (!hasNext()) { throw new NoSuchElementException(); } int result = current.data; current = current.next; removeOK = true; return result; } // pre : next() has been called without a call on remove (i.e., at most // one call per call on next; throws IllegalStateException if // not) // post: removes the last element returned by the iterator public void remove() { if (!removeOK) { throw new IllegalStateException(); } ListNode prev2 = current.prev.prev; prev2.next = current; current.prev = prev2; size--; removeOK = false; } } }