自定义LinkedList类first节点引用为空及last节点异常问题求助
Hey Tony, let's walk through the issues in your LinkedList code one by one—most of your problems come from accidental modifications to your first/last pointers and incorrect node linking:
1. The size() method is destroying your first pointer
Your size() method modifies the class-level first variable directly when traversing:
public int size(){ int c = 0; while(first != null){ first = first.next; // This moves the original first pointer to null after traversal! c++; } return c; }
After calling L.size(), your first node gets set to null—that's why all subsequent operations fail. Never modify your core list pointers when just reading data. Instead, use a temporary variable to traverse:
public int size(){ int c = 0; Node current = first; // Use a temp variable instead of modifying first while(current != null){ current = current.next; c++; } return c; }
2. Incorrect addLast() implementation
Your addLast() has two critical bugs:
- You traverse the list (unnecessarily, since you have a
lastpointer) and then create two separate new nodes: one forlast.nextand another forlastitself. This disconnectslastfrom the actual list. - You don't handle the case where
firstis null properly (the code after the if block will run even ifpis null, causing a NullPointerException).
Fix it by leveraging your last pointer directly:
public void addLast(T value){ Node newNode = new Node(value, null); if(first == null){ // List is empty first = last = newNode; return; } // Link the new node to the end, then update last last.next = newNode; last = newNode; }
3. Broken constructor
Your constructor creates two separate nodes for first and last, which means your initial list has two disconnected nodes with the same value:
public LinkedList(T value) { temp = new Node(value,null); first = new Node(value,null); last = temp; }
Simplify it to create a single node and point both first and last to it:
public LinkedList(T value) { Node initialNode = new Node(value, null); first = initialNode; last = initialNode; temp = initialNode; // If you even need temp—looks like it's unused in your code }
(Side note: The temp variable seems unused; you can probably remove it entirely to avoid confusion.)
4. Minor issue: remove() edge case handling
When removing the last node, you need to update the last pointer to point to the previous node. Otherwise, last will still reference the removed node. We added this logic to the helper removeLL() method.
Fixed Full Code
Here's the corrected version of your class with all fixes applied:
public class LinkedList<T> { Node first, last; // Removed unused temp variable public class Node { T value; Node next; public Node(T value, Node next) { this.value = value; this.next = next; } public String toString() { if (next == null) { return value.toString(); } else { return value.toString() + " " + next.toString(); } } public T getLL(int index) { if (index == 0) { return value; } if (next == null) { throw new IndexOutOfBoundsException("have reached the end of the list, none found"); } return next.getLL(index - 1); } // Helper method to handle remove and update last if needed public T removeLL(int x, LinkedList<T> list) { if (x == 1) { T removedValue = next.value; // If we're removing the last node, update list.last if (next == list.last) { list.last = this; } next = next.next; return removedValue; } else if (next == null) { throw new IndexOutOfBoundsException("have reached the end of the list, none found"); } else { return next.removeLL(x - 1, list); } } } public LinkedList(T value) { Node initialNode = new Node(value, null); first = initialNode; last = initialNode; } public static void main(String[] args) { /** * [120,110,100,90,80]; */ LinkedList<Integer> L = new LinkedList<>(100); // Use generic type to avoid warnings L.addFirst(110); L.addFirst(120); L.addLast(90); L.addLast(80); System.out.println(L.size()); // Should print 5 System.out.println(L.remove(0)); // Should print 120 System.out.println(L.last.toString()); // Should print 80 System.out.println(L.first.toString()); // Should print 110 100 90 80 } public void addFirst(T value) { first = new Node(value, first); // If list was empty before, update last too if (last == null) { last = first; } } public void addLast(T value) { Node newNode = new Node(value, null); if (first == null) { first = last = newNode; return; } last.next = newNode; last = newNode; } public T get(int index) { if (first == null) { throw new IndexOutOfBoundsException("empty list"); } return first.getLL(index); } public int size() { int c = 0; Node current = first; while (current != null) { current = current.next; c++; } return c; } public T remove(int x) { if (first == null) { throw new IndexOutOfBoundsException("Tried to remove from empty list"); } if (x == 0) { T removedValue = first.value; first = first.next; // If list is now empty, update last if (first == null) { last = null; } return removedValue; } return first.removeLL(x, this); } }
Why This Works
- The
size()method no longer modifies the originalfirstpointer. addLast()correctly links new nodes to the end of the list and updateslastproperly.- The constructor initializes
firstandlastto the same node, so your initial list is properly linked. - We added handling to update
lastwhen removing the last node, keeping your list pointers consistent.
内容的提问来源于stack exchange,提问作者Tony

