Link Menu Search Expand Document

LinkedIntList and loops

ed Lesson

Table of contents


Review

In the previous lesson, we introduced the ListNode class, a fundamental building block for LinkedIntList.

Implementer

public class ListNode {
    public int data;
    public ListNode next;
}

We also saw how to create integer sequences by creating and connecting multiple ListNode instances.

Implementer

ListNode list;
list = new ListNode();
list.data = 42;
list.next = new ListNode();
list.next.data = -3;
list.next.next = new ListNode();
list.next.next.data = 17;

Traversal

Creating new ListNode instances by hand is very tedious. Let’s automate some of the work of creating a sequence of ListNode instances by combining them with loops.

Suppose we have a variable list with many nodes that we want to print out. We could start by trying to write something like:

Implementer

System.out.print(list.data + " ");
System.out.print(list.next.data + " ");
System.out.print(list.next.next.data + " ");
System.out.print(list.next.next.next.data + " ");
...

This code is quite brittle: it only works if the number of print statements is exactly the same as the size of the list.

What happens if the number of print statements is greater than the size of the list?

Eventually, one of the list...next fields will be null, representing the end of the list. Java will throw a NullPointerException when the code attempts to access the data field of that null reference.

Instead, we will need a new approach that traverses the list by looking at each element one at a time.

Standard traversal for linked lists
Use a local variable to traverse the list. At each ListNode, perform some computation (like printing) before moving to the next node.

Implementer

ListNode current = list;
while (current != null) {
    System.out.print(current.data + " ");
    current = current.next;
}

current is the variable whose value is a reference to the current node. It begins at the front of the list. At the end of each iteration of the loop, current is reassigned to the next node in the list.

The loop ends when we reach null. We need to perform this check since the code inside of the loop requires access to current.data and current.next, which will only work if current is not null.

LinkedIntList class

Like ArrayIntList, the purpose of the LinkedIntList class is to provide a seamless implementation of a list of integers. ArrayIntList achieved this by maintaining an internal elementData array and size field to represent the data contained in the list ADT. We’ll see how we can achieve this result by maintaining ListNode instances instead of an array. The client should ultimately be able to write code that uses the LinkedIntList without knowing any of the implementation, just as we were able to use Java’s LinkedList class without knowing anything about nodes.

The LinkedIntList class maintains a single ListNode field, front.

Implementer

public class LinkedIntList {
    private ListNode front;

    public LinkedIntList() {
        front = null;
    }
}
In ArrayIntList, we kept track of the size as a field. Why is size not necessary here?

size is not necessary for LinkedIntList since each element of the sequence will have its own ListNode instance. The list ends when we hit the null pointer at the end of the sequence. As a rule, we’ll make sure that every ListNode in the LinkedIntList represents one element in the list ADT.

How might we implement the print method for LinkedIntList? We can use the standard traversal, but modify it so that current starts from the front of the LinkedIntList.

Implementer

public class LinkedIntList {
    private ListNode front;

    public LinkedIntList() {
        front = null;
    }

    public void print() {
        ListNode current = front;
        while (current != null) {
            System.out.print(current.data + " ");
            current = current.next;
        }
        System.out.println();
    }
}

For the rest of this lesson, we’ll focus on implementing the add method.