// A LinkedIntList object represents an ordered list of linked nodes. // Like ArrayIntList, LinkedIntList is an implementation of the List ADT. public class LinkedIntList { private ListNode front; // Constructs an empty list. public LinkedIntList() { front = null; } // Builds a new LinkedIntList with the specified number of nodes. // Node values start at n and decrease in value. // pre: n >= 0 public LinkedIntList(int value) { // LinkedIntList(5): 5 -> 4 -> 3 -> 2 -> 1 -> 0 // front == null for (int i = 0; i <= value; i++) { front = new ListNode(i, front); } } // Returns a comma-separated String representation of this list. public String toString() { if (front == null) { return "[]"; } else { String result = "[" + front.data; ListNode current = front.next; while (current != null) { result += ", " + current.data; current = current.next; } result += "]"; return result; } } // Adds the given value in sorted order, duplicates allowed. // pre: list is sorted in non-descending order // post: list is sorted public void addSorted(int value) { // cases: middle, front, empty, end // empty case: front == null // front case: value < front.data // robust case || weaker case if (front == null || value < front.data) { front = new ListNode(value, front); } else { ListNode current = front; // middle case: value > current.next.data // end case: current.next != null // again, robust case goes first while (current.next != null && value > current.next.data) { current = current.next; } current.next = new ListNode(value, current.next); } } // Add the given value to the end of the list. public void add(int value) { // adding at the end, size if (front == null) { front = new ListNode(value); } else { // list wasn't empty; find the back ListNode current = front; while (current.next != null) { current = current.next; } current.next = new ListNode(value); } } /* The following three methods we did not write in class, but you should be able to understand them at this point. */ // Returns the value at a given index // pre: 0 <= index < number of nodes; front != null, // throws IllegalArgumentException otherwise public int get(int index) { if (index < 0) { throw new IllegalArgumentException(); } ListNode current = front; for (int i = 0; i < index; i++) { current = current.next; } return current.data; } // Adds a value at a given index. // pre: 0 <= index <= size, throws IllegalArgumentException otherwise public void add(int index, int value) { if (index < 0) { throw new IllegalArgumentException(); } // get to the index // add to the index // what if index == 0? front case // empty case, check if (front == null || index == 0) { front = new ListNode(value, front); } else { // list wasn't empty; find the back ListNode current = front; for (int i = 0; i < index - 1; i++) { current = current.next; if (current == null) { throw new IllegalArgumentException(); } } // current.next = new ListNode(value, current.next); ListNode temp = new ListNode(value); temp.next = current.next; current.next = temp; } } // pre : 0 <= index < size // post: removes the element at index public void remove(int index) { // get to index // remove at index // one we're gonna remove, the one before, and the one after // index == 0? if (index == 0) { // front == null? no. front.next == null? mos def // that's okay! Won't throw a NPE to assign something to null front = front.next; } else { ListNode current = front; for (int i = 0; i < index - 1; i++) { current = current.next; } // hulk smash! current.next = current.next.next; } } // returns the size of the list public int size() { // front int size = 0; // start ListNode current = front; // end; rather, keep going // no need to stay one ahead; we don't need to change the list while (current != null) { // move size++; current = current.next; } // the real end return size; } }