public void add(int value) { if (front == null) { front = new ListNode(value); } else { ListNode current = front; while (current.next != null) { current = current.next; } current.next = new ListNode(value); } }This is very inefficient. To add something, we have to repeatedly traverse the whole list until we reach the last node. Wouldn't it be better if we just kept a pointer to the last node at all times?
The new class declaration (with changes highlighted) will be:
public class LinkedIntList { private ListNode front; private ListNode back; <methods> }The constructor would have to initialize the back pointer:
public LinkedIntList() { front = null; back = null; }And now the add method can be made much more efficient at the cost of a single pointer!
public void add(int value) { if (front == null) { front = new ListNode(value); back = front; } else { back.next = new ListNode(value); back = back.next; } }The remove method does not experience any increases in efficiency (ask yourself why), but care must be taken to make sure that the back pointer is updated properly when the node to be removed is being pointed to by back.
public void remove(int index) { if (index == 0) { front = front.next; // if front is null, then there was only one node // in the list, and therefore back must have been // pointing to it too. Reset back to null. if (front == null) { back = null; } } else { ListNode current = front; for (int i = 0; i < index - 1; i++) { current = current.next; // if current.next is the same node as that pointed // to by back, then the last node is being removed, // and back should be set to the prior node, namely // current if (current.next == back) { back = current; } current.next = current.next.next; } } }
public LinkedIntList() { front = new ListNode(); }Why is this at all useful? In writing the add method, we had to consider the case when front was null. Now, front can never be null! There is always at least one node there. The add method can be modified as follows:
public void add(int value) {For clarity:if (front == null) {front = new ListNode(value);} else {ListNode current = front; while (current.next != null) { current = current.next; } current.next = new ListNode(value);}}
public void add(int value) { ListNode current = front; while (current.next != null) { current = current.next; } current.next = new ListNode(value); }The addSorted method can also be modified to eliminate the initial checks of null and looking at the first node:
public void addSorted(int value) { ListNode current = front; while (current.next != null && current.next.data < value) { current = current.next; } current.next = new ListNode(value, current.next); }
Here is the old way:
public void print() { ListNode current = front; while (current != null) { System.out.print(current.data + " "); current = current.next; } }What is wrong with this code? The while is supposed to stop when current == null, however, unless the list is empty, current will NEVER be null! It will loop forever and ever and ever.
Here's the fix:
public void print() { ListNode current = front; while (current != null) { System.out.print(current.data + " "); current = current.next; if (current == front) { break; } } }Note that that isn't the only solution. Here is another way:
public void print() { if (front != null) { System.out.print(front.data + " "); ListNode current = front.next; while (current != front) { System.out.print(current.data + " "); current = current.next; } } }When testing programs, always check that it works for all cases. In particular,