Concepts / Linked Structures and Pointers

Linked Structures and Pointers

ArrayList and LinkedList implement the same List operations but store items differently: a growing contiguous array versus nodes joined by pointers.

  • Programming

Why Two Classes Hold the Same Kind of Sequence

Suppose you need to keep an ordered collection of items in a program: a playlist, a queue of print jobs, or a row of records loaded from a file. Java provides more than one class that can hold such a sequence. Two of the most common are java.util.ArrayList and java.util.LinkedList. Both implement the same List interface, so they share the same set of operations, and a program can often call the same methods on either one.

Yet the two classes behave very differently in speed, and that difference is the reason both exist. The underlying question is this: if the operations are identical, why not build one list class? The answer is that no single internal design makes every operation fast. Each design makes some operations cheap and others expensive. So the practical skill is not memorizing which class is better. It is recognizing which operations your program will repeat most often, and then picking the design that makes those operations cheap.

What do you think happens?

Both classes expose the same methods. Which one would you expect to be faster when your program repeatedly asks for the item at position 7?

  • ArrayList

  • LinkedList

  • They are equally fast

Reveal answer
Answer:

ArrayList

An ArrayList keeps its items in one contiguous block, so it can locate slot 7 directly. A LinkedList has to follow pointers from the first node through several nodes before reaching position 7. The sections below trace exactly why.

How an ArrayList Lays Out Its Items

An ArrayList keeps its items in one contiguous block of storage, behaving like a row of numbered slots. Slot 0 holds the first item, slot 1 holds the second, and so on. The row can grow: when it fills up, the list obtains a larger row and copies the items across. From the programmer's point of view you simply keep adding items and the list takes care of the growing. Internally, though, the items sit side by side, and that arrangement is what makes positions so easy to compute.

Aslot 0Bslot 1Cslot 2Dslot 3
Each item occupies a numbered slot, and neighboring slots sit next to each other. Because the cells are in order, the list never has to search for an item; it only needs the position number.

The important feature is adjacency. Slot 2 sits directly after slot 1 in the same block, so the list does not need to examine slots 0 and 1 to know where slot 2 is. Keep this picture in mind, because the rest of the comparison follows from it.

Nodes and Pointers in a LinkedList

A LinkedList takes a completely different approach. Instead of one block of adjacent cells, it stores each item in its own small container called a node. Every node holds an item and also a pointer, meaning a reference, to the next node in the sequence. The list itself only needs to remember where the first node is. Everything after that is reached by following the pointers from one node to the next.

Definition

A node is a small container that holds one item and a pointer (a reference) to the next node in the sequence. A linked structure is a collection of such nodes in which the pointers, rather than physical adjacency, define the order of the items.

Because the nodes are not required to sit next to each other, they can be scattered anywhere. What holds the sequence together is the chain of pointers. Picture a node holding value A whose pointer leads to a node holding B, whose pointer leads to a node holding C, and so on. The end of the chain is the last node, which has no next node to point to.

This arrangement is the key to the LinkedList's strengths and weaknesses. Changing where one node points is a local change that does not disturb the rest of the chain. Finding a node, on the other hand, requires walking the chain one link at a time.

Reaching Position k in Each Structure

Random access means getting or changing the item at a specified position k. Whenever a program asks for the item in slot 7, or wants to overwrite the item at position 12, it is doing random access. This is where the two structures diverge most sharply.

slot 0item Aslot 1item Bslot 2item Cslot 3item Dslot 4item Eslot 5item Fslot 6item Gslot 7item H
To answer get(7), the list computes where slot 7 lives and reads it directly, without visiting slots 0 through 6.

For an ArrayList, random access is essentially immediate. The list knows exactly where slot k lives because the cells are contiguous, so the time needed does not depend on how many items the list holds. This is written Theta(1), a constant amount of work. Slot 7 costs about the same as slot 0.

For a LinkedList there is no shortcut. To reach position k, the program must start at the first node and follow pointers forward k times. Picture a LinkedList holding A, B, C, D, E, F, G, H. To reach H at position 7, the walk goes: start at the first node (A), follow to B, follow to C, follow to D, follow to E, follow to F, follow to G, and follow once more to H. That is seven pointer follows. A position near the front is reached quickly, while a position near the back takes a long walk. The work grows with k, which is written Theta(k).

Inserting in the Middle: Shifting Versus Relinking

Changing the middle of a list is where the LinkedList earns its place. Consider what it takes to insert a new item between two existing items. In an ArrayList, the new item needs a free slot at the correct position, so every item from that point onward must move one position to make room. The cost depends on how many items sit after the insertion point. Inserting at the beginning forces the most movement, because every item shifts. Writing this cost as Theta(n) means the time grows in step with the number of items n.

Aslot 0Aslot 0Bslot 1Xslot 1 (new)Cslot 2Bslot 2 (moved)Dslot 3Cslot 3 (moved)Dslot 4 (moved)
Before the insert, B, C and D sit in slots 1 to 3. After X is inserted at index 1, X takes that slot and every later item has moved one position to the right.

In a LinkedList, the same insertion is a matter of re-pointing a few links. The new node is created, its pointer is set to the node that should follow it, and the pointer of the node before it is changed to point to the new node. Inserting X between A and B means setting X's pointer to B and changing A's pointer to X. Nothing else moves. A handful of pointer updates is enough regardless of how long the list is. That is why these changes take Theta(1) time once the program is already standing at the spot where the change belongs.

Mistakes When Choosing a List

  • Common mistake

    Assuming LinkedList is always faster for insertions

    What it looks like

    Adding a new item at the front of a large list in a loop, then assuming the LinkedList will be cheap because it is a linked structure.

    Why it fails

    Insertion is constant time only once the program is already at the right spot. If the program has to walk k nodes to find the position, the search cost of Theta(k) is paid before any relinking happens.

    Do this instead

    Count the whole operation, including locating the position, before deciding which structure is cheaper.

  • Common mistake

    Assuming ArrayList insertion is always slow

    What it looks like

    Appending items to the end of an ArrayList in a loop and expecting each append to shift everything.

    Why it fails

    Adding at the end is efficient for both classes. An ArrayList appends into the next free slot, so no existing items move.

    Do this instead

    Separate the costly case, inserting or removing in the middle, from the cheap case, appending at the end.

  • Common mistake

    Choosing a structure by memorizing which class is better

    What it looks like

    Picking LinkedList because it sounds more advanced for a program that mostly reads items by index.

    Why it fails

    No single internal design makes every operation fast. The right choice depends on which operations the program repeats most.

    Do this instead

    List the operations your program repeats most often, then choose the structure that makes those cheap.

  • Common mistake

    Forgetting that a LinkedList must walk from the first node to reach any position beyond the front

Matching the List to the Workload

OperationArrayListLinkedList
Get or set item at position kTheta(1), direct slot computationTheta(k), walks k nodes from the first node
Insert or remove in the middleTheta(n), later items shiftConstant time once the node is located, found by walking
Add at the endEfficient, fills the next free slotEfficient, attaches after the last node
Sorting the itemsEfficientEfficient
Internal storageOne contiguous block that growsNodes joined by pointers

Operation costs for the two List implementations, as described in the source.

Read this table against your own program. If the work is dominated by reading items by position, such as looking up slot 7 many times, the ArrayList's constant-time access is the decisive advantage. If the work is dominated by inserting or removing in the middle of the sequence, the LinkedList's cheap relinking is the advantage. If the work is mostly appending and sorting, both classes perform well, and other design choices will probably matter more than this one.

Practice Choosing a Structure

MEDIUM

A program keeps a queue of print jobs. Jobs are appended at the back, and the program frequently removes a job from the middle when a user cancels it. It rarely reads jobs by position. Which list type would you choose, and what operation's cost drives your decision? Explain your reasoning in terms of the cost of finding the position and the cost of changing the list.

Hints
  • Think about which operation dominates: appends, reads by index, or removals from the middle.
  • Removal from the middle in an ArrayList means later items must shift, costing Theta(n).
  • In a LinkedList, a removal costs little once the node is found, but finding a node in the middle still requires a walk.
EASY

Explain, without looking back, why get(0) costs about the same on an ArrayList holding a million items as on one holding ten items, but get(999999) on a LinkedList costs far more than get(0).

Hints
  • Consider whether the ArrayList must visit earlier slots to find slot k.
  • Consider how many pointer follows the LinkedList needs to reach the front versus the far end.

Key Takeaways

  • An ArrayList stores items in one contiguous, growing block of numbered slots, so reading or writing position k is constant time, Theta(1).
  • A LinkedList stores each item in a node holding a value and a pointer to the next node, so reaching position k means walking k nodes, Theta(k).
  • Inserting or removing in the middle is costly for an ArrayList, Theta(n), because later items shift, while a LinkedList can relink a few pointers in constant time once the position is found.
  • Appending and sorting are efficient for both classes, so choose the structure by which operations your program repeats most often.