ma'am audrey's lessons

ITC 120 › Prelim › Linked lists

Linear data structures · Lesson 2 of 4

Linked lists

This lesson teaches:Data structureAlgorithm

A chain of nodes. Nothing shifts: we change the arrows instead.

By the end, you can:

  1. explain how nodes and references form a linked list;
  2. trace access, traversal, insertion, and deletion on a box-and-arrow drawing and in Java, and write a method that adds a node at the end;
  3. compare a linked list with an array: which tasks each one does faster, and when to use each;
  4. explain why the order of the lines matters when inserting;
  5. tell singly, doubly, and circular linked lists apart.

You need: the Arrays lesson, and scratch paper for drawing boxes and arrows.

Part 1 · The idea

A chain of nodes

The array's one real weakness: to insert 25 at index 2 of 10, 20, 30, 40, both 30 and 40 had to move. The more values after the gap, the more work. So what if the values did not have to sit side by side at all?

Insert 25 at index 2 of an arrayBefore1020304001234After10202530401230 and 40 had to move (40 first).More values after the gap = more moves.
The array's weakness: every value after the gap moves.

Linked list

A linked list is a linear data structure (a way to organize data where the items form one line, each item followed by at most one next item) made of a chain of nodes. A node is one small box of data in the chain. Each node stores two things: the value (data), and where to find the next node (next). A variable called head refers to the first node. The last node's next is null: the end. An empty list has head equal to null.

A linked listheadABCnullhead refers to the first node.null means no next node: the end.One node, up close (B)BCdatathe valuenextwhere to findthe next node
head refers to the first node. Each node holds data and next. null marks the end.

Like a treasure hunt

Each clue tells you where the next clue is hidden. To reach clue 4, you start at clue 1 and follow the clues in order. You cannot jump to clue 4. The first clue is like head, each hiding place is like next, and "this is the last clue" is like null.

A treasure hunt at schoolClue 1Next: canteenat the flagpoleClue 2Next: mango treeat the canteenClue 3Next: libraryunder the mango treeClue 4The end!at the libraryClue 1 is where you start: like head.Each clue says where the next one is: like next."The end!" means no more clues: like null.
Follow the clues in order. You cannot skip to clue 4.

Here is the same sequence, organized two ways:

Seat plan: like an array0Ana1Ben2Cris3DanSeat 2? Walk straight to it. One step.A train: like a linked listenginecar 1car 2car 3empty hookhooksThe engine is like head. Each hook is like next.The empty hook at the end is like null.To reach car 3, go car by car.
A seat plan jumps straight to a seat. A train is walked car by car.

Side by side:

ArrayLinked list
Numbered slots, side by side.Nodes can be anywhere in memory.
The index tells you where to go.The previous node tells you where to go next.
Reach any slot in one step.Walk from head, one link at a time.
Insert or delete: shift values.Insert or delete: change links.

Part 2 · Java first

Nodes and references in Java

Before the code, two words you will use in every lesson from now on: class and object. Think of a polvoron mold. You cannot eat the mold; it only decides the shape. Each time you press it, you get one real polvoron, and each one can have its own flavor.

One mold, many polvoronthe moldclass Nodeubepinipigplainneweach one: an objectSame shape every time, but each has its own flavor.
The mold is like a class. Each polvoron is like an object: the same shape every time, but its own flavor.

Class and object

A class is a blueprint: it describes what every object of that kind will have (its fields, the variables inside each object) and what it can do (its methods). An object is one real thing made from the class with new. One class can make many objects, and each object keeps its own values.

In this lesson, the class is Node, and every node in a list is one object made from it. Here is the class:

 1class Node {
 2  int data;          // the value stored in this node
 3  Node next;         // reference to the next node (null if none)
 4
 5  Node(int value) {  // constructor: runs once for each new Node(...)
 6    data = value;
 7    next = null;     // a new node has no next node yet
 8  }
 9}

Reference

A reference tells Java where to find an object. It is not the object itself. The special value null refers to no object.

LineMeaning
int data;A field: a variable inside each node object. It holds that node's value, and every node has its own.
Node next;A field that holds a reference to another node, or null.
Node(int value)The constructor: same name as the class, no return type. It runs once, automatically, each time new Node(...) runs.

Each new makes one more object from the same blueprint:

class Node: the blueprintint data;Node next;Node(int value) { ... }no real node yetnew Node(10)datanext10nullobject 1new Node(20)datanext20nullobject 2One class, many objects. Each object has itsown data: changing one does not change the other.
One class, two objects. Each node has its own data and its own next.

Node first = new Node(10); does three things: new creates a node in memory, the constructor stores 10 in data and null in next, and = stores a reference to that node in the variable first. (The name first is our choice, not a Java keyword.)

Node first = new Node(10);1newmakes an emptynode in memorydatanext2constructorstores 10 in data,null in nextdatanext10null3=stores thereference in firstdatanext10nullfirst
One line, three jobs.

Assignment copies the reference, not the node

Node a = new Node(5);
Node b = a;                  // b refers to the SAME node as a
b.data = 9;                  // changes that one node
System.out.println(a.data);  // prints 9
Node b = a;b.data = 9;Node b = new Node(5);b.data = 9;ab9one person,two nameshis shirt: 5 → 9a.data is 9 tooab59two people,one name eachonly b's shirt: 5 → 9a.data stays 5
Same node, two names vs. two separate nodes. The shirt number is the data.

Node b = a; does not make a new node. It gives the same node a second name. Like a classmate with two names, Migs and Miguel: if Migs gets a new shirt number, Miguel has it too, because they are the same person. Compare Node b = new Node(5);, which makes a separate node: changing b.data would not touch a.data.

The dot in b.data means "the data field of the node that b refers to." (In the Stacks lesson, objects also have methods, and the dot runs them: s.push(4).)

Connecting two nodes

Node ten = new Node(10);
Node twenty = new Node(20);
ten.next = twenty;           // connects node 10 to node 20
10→20→null

ten.next now stores a reference to node 20, not the number 20. The number is ten.next.data.

NullPointerException

An exception is an error Java reports while the program is running; if nothing handles it, the program stops. If a reference is null, using .data or .next on it throws (reports) a NullPointerException, and the program stops at that line. Before writing x.next, ask: can x be null here?

Part 3 · Operations 1 and 2

Accessing and traversing a linked list

Access and traversal

Access means getting one item. Traversal means visiting every item, one by one, in order. You met in the Arrays lesson. In a linked list, both start at head and follow the next links.

Traversal: visit every nodehead102030nullprint 10print 20print 30stopVisit a node, follow next, repeat. Stop at null.
Traversal visits every node, then stops at null.

This code builds the list 10 → 20 → 30 and prints it. We keep the name twenty for node 20, so later steps can use it without searching.

Node head = new Node(10);    // head refers to node 10
Node twenty = new Node(20);
head.next = twenty;          // 10 -> 20
twenty.next = new Node(30);  // 20 -> 30
printList(head);             // 10 -> 20 -> 30 -> null

Here is printList:

 1static void printList(Node start) {
 2  Node current = start;              // start at the first node
 3  while (current != null) {          // while there is a node here
 4    System.out.print(current.data + " -> ");
 5    current = current.next;          // move to the next node
 6  }
 7  System.out.println("null");        // mark the end
 8}

When main calls printList(head), start gets a copy of head's reference. Then current copies it again. All three refer to node 10, but they are separate variables. current = current.next; moves only current. It does not move any node, and it does not change head.

Two words in the first line: static lets main call printList directly, without making an object first, and void means it sends no value back (it only prints). Also, each method has its own variables: the current inside printList is separate from the current that main declares later in the whole program, even though the names match.

Step through it on the list 10 → 20 → 30. Watch current (orange) move while head and start stay on node 10.

Walkthrough: printList(head) on 10 → 20 → 30

Use Next to go step by step, or tap a line to jump to it.

currentstarthead102030null Output

current → 10

start got a copy of head's reference. current copies it again: all three refer to node 10.

Step 1 of 10
 1static void printList(Node start) { 2  Node current = start; 3  while (current != null) { 4    System.out.print(current.data + " -> "); 5    current = current.next; 6  } 7  System.out.println("null"); 8}
Show the same walk in one table
currentThis step printsThen
1010 -> move to 20
2020 -> move to 30
3030 -> 30's next is null, so current becomes null
null(the loop stops)print null

Output: 10 -> 20 -> 30 -> null

Forgetting current = current.next;

Without that line, current never moves. It stays on node 10, so current != null is true forever: the loop prints 10 -> again and again and never ends.

Walkthrough: the loop without the move line

Use Next to go step by step, or tap a line to jump to it.

currenthead102030null Output

current → 10

current starts at node 10, like before.

Step 1 of 5
 1Node current = head; 2while (current != null) { 3  System.out.print(current.data + " -> "); 4  // forgot: current = current.next; 5}

null, two ways

In current != null, null is a reference value: "no node." In System.out.println("null"), it is just text in quotation marks that the program prints.

null as a value: current != null102030nonecurrentAfter 30, current is null: it refers to no node.So current != null is false, and the loop stops.null as text: println("null")10 -> 20 -> 30 -> nullAfter the loop, the program just types thefour letters n u l l to show where the list ends.
Same word, two jobs.

Access is the same walk, stopped early: to get the third node, start at head and follow two links. An array reaches arr[2] in one step. A linked list walks.

Access: get the 3rd nodehead102030null1st2nd3rdhop 1hop 2Start at head (the 1st node). 2 hops later: the 3rd. Stop.
Access stops at the node it needs.

Part 4 · Operation 3

Insertion: change links, not values

Insert at the beginning

Start with 10 → 20 → 30. Insert 5 before 10:

Walkthrough: insert 5 at the beginning

Use Next to go step by step, or tap a line to jump to it.

newNodehead5null102030null

newNode → 5

new makes node 5. Its next is null, so it is not connected to the list yet. head still refers to 10.

Step 1 of 3
 1Node newNode = new Node(5); 2newNode.next = head;   // step 1 3head = newNode;        // step 2

Nothing shifted. Two references changed.

Swap the lines, and the list is lost

If head = newNode; runs first, then newNode.next = head; copies the new head, so node 5 refers to itself. Nothing refers to node 10 anymore, and printList(head) prints 5 forever.

Walkthrough: the same lines, swapped

Use Next to go step by step, or tap a line to jump to it.

newNodehead5null102030null

newNode → 5

Same start as before: node 5 exists, but it is not connected yet.

Step 1 of 3
 1Node newNode = new Node(5); 2head = newNode;        // WRONG: done first 3newNode.next = head;

Insert after a node you already have

Start with 10 → 20 → 30, and current refers to node 20. Insert 25 after it:

Walkthrough: insert 25 after node 20

Use Next to go step by step, or tap a line to jump to it.

headcurrent102030null

current → 20

Start with 10 → 20 → 30. We already have current on node 20, so no search is needed.

Step 1 of 4
 1// current refers to node 20 2Node newNode = new Node(25); 3newNode.next = current.next;   // step 1 4current.next = newNode;        // step 2

current.next is the reference stored in node 20, which refers to node 30. So line 3 makes 25 refer to 30. Then line 4 makes 20 refer to 25. Result: 10 → 20 → 25 → 30.

Here we already had a reference to node 20. To insert after a value, you would first traverse to find that node.

The safe order for inserting

  1. First, make the new node refer to the node that will follow it.
  2. Then, change the old reference to point to the new node.

If B is the only thing pointing to C, and you change B first, nothing points to C anymore. The rest of the list is unreachable. You can watch it happen with "Insert: wrong order!" in the lab (Part 6).

✓ Grab, then let go✗ Let go first1 grab2 let goStill holding on:safe!!Nothing to hold: you fall.Insert 25 between 20 and 30: first 25 → 30 (grab),then 20 → 25 (let go). Never let go first.
Grab the next bar before you let go.

Part 5 · Operation 4

Deletion: link around the node

Delete the node after another one

Take car 2 out of the traincar 1car 2 (out)car 3new hook: car 1 → car 3Only car 1's hook changes.Car 2 is no longer in the train.
Deleting is like unhooking a train car.

Start with 10 → 20 → 25 → 30. To delete 25, we need a reference to the node before it, because a singly linked list cannot go backward. previous refers to node 20:

Walkthrough: delete the node after 20

Use Next to go step by step, or tap a line to jump to it.

headprevious102030null25

previous → 20

Start with 10 → 20 → 25 → 30. To delete 25, we need the node before it: previous is on 20.

Step 1 of 3
 1// previous refers to node 20 2previous.next = previous.next.next;

Read it piece by piece: previous.next is node 25. previous.next.next is node 25's next, which is node 30. Storing that in previous.next makes 20 point to 30. Node 25 is no longer reachable from head, so it is no longer in the list. Nothing else moves.

Is node 25 gone? It is out of the list. Once nothing at all refers to a node, Java's garbage collector (the part of Java that cleans up unused objects) frees its memory later. You do not delete it yourself. (In the whole program below, the variable newNode still refers to node 25, so that node still exists for now.)

This line needs previous != null and previous.next != null. Otherwise it uses a null reference and throws a NullPointerException.

Delete the first node

Deleting the first node only moves head:

head = head.next;    // head refers to the second node

5 → 10 → 20 → 30 becomes 10 → 20 → 30. This needs head != null (a list that is not empty). If the list had only one node, head becomes null: the list is now empty.

The whole program

Here is everything together. The program runs all four operations one after another on one list, so its lists are a little longer than the short examples above. Run it and match each output line to its printList call.

Show the complete program
 1class Node {
 2  int data;
 3  Node next;
 4  Node(int value) {
 5    data = value;
 6    next = null;
 7  }
 8}
 9
10public class Main {
11  static void printList(Node start) {
12    Node current = start;
13    while (current != null) {
14      System.out.print(current.data + " -> ");
15      current = current.next;
16    }
17    System.out.println("null");
18  }
19
20  public static void main(String[] args) {
21    Node head = new Node(10);
22    Node twenty = new Node(20);
23    head.next = twenty;
24    twenty.next = new Node(30);
25    printList(head);
26
27    // 1. insert 5 at the beginning
28    Node newNode = new Node(5);
29    newNode.next = head;
30    head = newNode;
31    printList(head);
32
33    // 2. insert 25 after node 20
34    Node current = twenty;
35    newNode = new Node(25);
36    newNode.next = current.next;
37    current.next = newNode;
38    printList(head);
39
40    // 3. delete the node after 20 (bypass it)
41    Node previous = twenty;
42    previous.next = previous.next.next;
43    printList(head);
44
45    // 4. delete the first node
46    head = head.next;
47    printList(head);
48  }
49}

▶ This program runs as is. Try it in the Programiz online compiler: tap Copy, paste it there, and press Run.

10 -> 20 -> 30 -> null
5 -> 10 -> 20 -> 30 -> null
5 -> 10 -> 20 -> 25 -> 30 -> null
5 -> 10 -> 20 -> 30 -> null
10 -> 20 -> 30 -> null

The real cost

Changing links is cheap. Finding the node is not:

With house numbers: like an array123…500go straight to #500One trip, no matter how long the street is.With directions only: like a linked list… #500123Each house only says which house is next.You must ask at every house on the way.
House numbers vs. directions.

Here is what each task costs:

TaskArrayLinked list
Get the value at index 500 (the 501st item)1 stepstart at head and follow 500 links
Insert at a spot you already reachedshift every later valuechange 2 links
Delete the last valuejust reduce the sizewalk to the node before it

Not always faster

Linked lists edit faster, once you are there. Arrays reach faster. Pick the one that fits what the program does most.

Part 6 · Watch it

The linked list lab

Now watch every operation from Parts 3 to 5 again, one line of Java at a time. Each button starts from a short list, so you can replay any of them. Try "Insert: wrong order!" to see happen.

Linked list lab

Pick an operation and tap Next step. Each step runs one line of Java. Watch which arrow changes.

Swipe the picture sideways to see the whole list.

Color key
node being changed or visited new node orange arrow = just changed unreachable from head

Part 7 · Three kinds

Singly, doubly, and circular

Singly: a one-way streetONE WAY →Forward only. To go back, start over from the head.Doubly: a two-way streetNext and back. Like a photo viewer.Circular: a loop routestartcomes back to the startNo end: a loop needs a rule for when to stop.
Three kinds, three kinds of road.

Singly linked

Each node knows only what comes next. It moves forward only. To reach the node before B, start over from the head. Like checking attendance from the top of the class list to the bottom.

Doubly linked

Each node also has a prev link, so it moves both ways. The cost: more memory, and more links to update on every change. Like a photo viewer with Next and Previous buttons.

Circular

The last node points back to the first. There is no null at the end, so a loop must stop when it gets back to where it started. Like a cleaning duty schedule that returns to the first name.

Singly: next onlyABCnullDoubly: prev and nextABCnullnullprevnextCircular: back to the firstABCno null anywhere
The same three kinds as nodes and arrows.

Here they are side by side:

SinglyDoublyCircular
Links per nodenextprev and nextnext, or both
Move backward?noyesonly if doubly
End of the listlast next is nullnull at both endsloops back to the first
Remove a node you haveneed the node before itdirectly, using prevdepends on singly or doubly
Trade-offone direction onlymore memory and updatesneeds a stop rule

Circular is not a third number of links

"Circular" describes the loop, not how many links each node has. A circular list can be singly or doubly linked. A playlist on repeat with Next and Previous is circular doubly linked.

Circular singly: next onlyABCC → back to ACircular doubly: prev and nextABCA.prev → back to CC.next → back to ABoth loop back, so both are circular.
Circular singly and circular doubly: both loop back.

Doubly and circular lists in Java (extra)

Extra topic. Writing doubly and circular lists in Java goes beyond this course. You only need to tell the three kinds apart and give a trade-off for each, as in the table above. Open this if you are curious.

Show doubly and circular lists in Java

The four operations are the same as in a singly list. Two things change: how many links you update, and how a loop knows when to stop.

Doubly linked: insert after a node. Each node has one new field, prev, the node before it. In a singly list, inserting after a node changed 2 links ( ). In a doubly list it changes 4: two for the new node, and one for each neighbor.

Before2030nextprevAfter insertAfter(20, 25)2025304213
Inserting 25 after 20. The four orange links are the ones that change, in the order of the code.

Here are the four changes, in order:

StepCodeIn words
1newNode.prev = current;25 looks back at 20
2newNode.next = current.next;25 looks ahead at 30
3current.next.prev = newNode;30 looks back at 25
4current.next = newNode;20 looks ahead at 25

The safe order is the same idea as before: give the new node its links first (steps 1 and 2), then point the neighbors at it (steps 3 and 4). If you do step 4 first, current.next is already 25, so step 2 makes 25 point at itself, and 30 is lost.

 1public class DoublyDemo {
 2  // insert newNode right after current: 4 links change
 3  static void insertAfter(DNode current, DNode newNode) {
 4    newNode.prev = current;          // step 1: 25 looks back at 20
 5    newNode.next = current.next;     // step 2: 25 looks ahead at 30
 6    if (current.next != null) {      // (no next node at the end)
 7      current.next.prev = newNode;   // step 3: 30 looks back at 25
 8    }
 9    current.next = newNode;          // step 4: 20 looks ahead at 25
10  }
11
12  public static void main(String[] args) {
13    DNode head = new DNode(20);
14    DNode tail = new DNode(30);
15    head.next = tail;
16    tail.prev = head;
17
18    insertAfter(head, new DNode(25));
19
20    DNode current = head;            // forward, using next
21    while (current != null) {
22      System.out.print(current.data + " ");
23      current = current.next;
24    }
25    System.out.println();            // 20 25 30
26
27    current = tail;                  // backward, using prev
28    while (current != null) {
29      System.out.print(current.data + " ");
30      current = current.prev;
31    }
32    System.out.println();            // 30 25 20
33  }
34}
35
36class DNode {
37  int data;
38  DNode prev;   // NEW: the node before this one
39  DNode next;
40
41  DNode(int value) {
42    data = value;
43    prev = null;
44    next = null;
45  }
46}

▶ Try it in the Programiz online compiler: tap Copy, paste it there, change public class DoublyDemo to public class Main (Programiz saves your code as Main.java, and Java needs the file name and the public class name to match), then press Run.

The if handles inserting after the last node: there is no next node, so there is no step 3. Deleting is shorter. To remove a node x that is not first or last, you need only x.prev.next = x.next; and x.next.prev = x.prev;. You do not have to search for the node before it, because x.prev already points to it.

Circular: walk the list once. In a circular list, current never becomes null, so the usual while (current != null) loop would print 10 20 30 10 20 30 … forever. Instead, print the first node, then stop when you are back at the head:

 1public class CircularDemo {
 2  public static void main(String[] args) {
 3    Node head = new Node(10);
 4    head.next = new Node(20);
 5    head.next.next = new Node(30);
 6    head.next.next.next = head;      // 30 points back to 10
 7
 8    System.out.print(head.data + " ");   // print the first node
 9    Node current = head.next;
10    while (current != head) {        // stop when back at the start
11      System.out.print(current.data + " ");
12      current = current.next;
13    }
14    System.out.println();            // 10 20 30
15  }
16}
17
18class Node {
19  int data;
20  Node next;
21
22  Node(int value) {
23    data = value;
24    next = null;
25  }
26}

▶ Try it in the Programiz online compiler: tap Copy, paste it there, change public class CircularDemo to public class Main (Programiz saves your code as Main.java, and Java needs the file name and the public class name to match), then press Run.

This loop assumes the list has at least one node. If head can be null, check that first.

How do the three kinds compare in speed? Once you have the node, inserting or deleting takes a few steps in all three kinds, however long the list is. Doubly does about twice the link work and stores one more reference per node. In return, it can go backward, and it can delete a node without searching for the one before it.

Part 8 · Your turn

Practice

Draw boxes and arrows for every problem. That is what you will do on the exam. The module's own "Check your understanding" items (Sections 3 and 4) are in the closed box below, in case you want to redo them. The "New problems" set is new. The last box is a short coding task you can do on a phone.

Show the module's practice (Sections 3 and 4)

Nodes and references

  1. What does this print? Explain why.
    Node p = new Node(3);
    Node q = new Node(3);
    q.data = 8;
    System.out.println(p.data);
  2. After these lines, how many Node objects exist? What is first.next.data?
    Node first = new Node(1);
    Node second = new Node(2);
    first.next = second;
    Node third = first.next;
  3. What happens when Node n = null; is followed by System.out.println(n.data);?
Show the answers
  1. It prints 3. new ran twice, so p and q refer to different nodes. Changing q.data does not affect p.
  2. Two nodes. third is just another reference to the second node. first.next.data is 2.
  3. A NullPointerException: n refers to no node. Nothing catches it here, so the program stops at that line.

Insert and delete

  1. Start with head → 10 → 20 → 30 → null. Draw the list after these three lines. Then draw it again after head = head.next;.
    Node n = new Node(15);
    n.next = head.next;
    head.next = n;
  2. Explain in your own words: newNode.next = current.next;
  3. In head → 10 → 20 → 30 → 40 → null, previous refers to node 20. Draw the list after previous.next = previous.next.next;. Which node is no longer reachable?
  4. Debugging. The list is head → 10 → 20 → 30 → null, current refers to node 20, and newNode refers to a new node 25 (its next is null). A student wrote these lines to insert 25 after 20. Draw the result. What goes wrong?
    current.next = newNode;
    newNode.next = current.next;
  5. Name the kind of linked list: (a) nodes have prev and next, and both ends hold null; (b) the last node's next refers to the first, and nodes have no prev; (c) a playlist on repeat with Next and Previous buttons.
Show the answers
  1. After the three lines: head → 10 → 15 → 20 → 30 → null (15 goes after the node head refers to). After head = head.next;: head → 15 → 20 → 30 → null.
  2. The new node now refers to the node that comes after current, so the rest of the list stays reachable before current is changed.
  3. head → 10 → 20 → 40 → null. Node 30 is no longer reachable from head.
  4. After current.next = newNode;, nothing refers to 30: it is lost. Then newNode.next = current.next; copies a reference to 25 itself, so 25 points to 25. The list reads 10 → 20 → 25 → 25 → …, and a traversal prints 25 forever.
  5. (a) Doubly linked. (b) Circular singly linked. (c) Circular doubly linked: it repeats (circular) and goes back (prev).

New problems

  1. The list is head → 4 → 9 → 16 → 25 → null. Write the three values printed, one per line. After the code, which node does head refer to?
    Node current = head.next;
    current = current.next;
    System.out.println(current.data);
    System.out.println(current.next.data);
    System.out.println(head.next.data);
  2. The list is head → 7 → 14 → null. Draw the list after these lines. Which line runs "connect the new node first"?
    Node a = new Node(3);
    a.next = head;
    head = a;
    Node b = new Node(10);
    b.next = head.next.next;
    head.next.next = b;
  3. The list is head → 2 → 4 → 6 → 8 → null. Draw the list after these lines. Which nodes are no longer reachable from head?
    head = head.next;
    Node prev = head.next;
    prev.next = prev.next.next;
Show the answers
  1. 16, 25, 9. current starts at 9 (head.next), then moves to 16. current.next.data is 25, and head.next.data is still 9. head still refers to node 4: only current moved.
  2. head → 3 → 7 → 10 → 14 → null. Lines 2-3 insert 3 at the beginning (new node first, then head). Line 5, b.next = head.next.next;, connects the new node first: head.next is 7, so head.next.next is 14. Then line 6 makes 7 refer to 10.
  3. head → 4 → 6 → null. The first line drops node 2. prev refers to 6, and prev.next.next is 8's next, which is null, so 6 now ends the list. Nodes 2 and 8 are no longer reachable from head. (This works because prev.next is not null.)

Your coding task: add to the end

Part 4 inserted at the beginning and after a given node. Now add a node at the end, like a new student joining the end of a line. Finish addLast in about 6 lines where it says YOUR CODE: handle the empty list first, then walk to the last node. Run it: the three printed lists must match the comments.

 1class Node {
 2  int data;
 3  Node next;
 4  Node(int value) {
 5    data = value;
 6    next = null;
 7  }
 8}
 9
10public class Main {
11  // Adds a new node with this value at the END. Returns the head.
12  static Node addLast(Node head, int value) {
13    Node newNode = new Node(value);
14    // YOUR CODE:
15    // 1. If the list is empty, the new node is the whole list.
16    // 2. Otherwise, walk to the last node (its next is null)
17    //    and make it refer to the new node.
18
19    return head;
20  }
21
22  static void printList(Node start) {
23    Node current = start;
24    while (current != null) {
25      System.out.print(current.data + " -> ");
26      current = current.next;
27    }
28    System.out.println("null");
29  }
30
31  public static void main(String[] args) {
32    Node head = null;              // an empty list
33    head = addLast(head, 10);
34    printList(head);               // expected: 10 -> null
35    head = addLast(head, 20);
36    printList(head);               // expected: 10 -> 20 -> null
37    head = addLast(head, 30);
38    printList(head);               // expected: 10 -> 20 -> 30 -> null
39  }
40}

▶ This program runs as is. Try it in the Programiz online compiler: tap Copy, paste it there, and press Run.

Show one possible answer
 1static Node addLast(Node head, int value) {
 2  Node newNode = new Node(value);
 3  if (head == null) {
 4    return newNode;
 5  }
 6  Node current = head;
 7  while (current.next != null) {
 8    current = current.next;
 9  }
10  current.next = newNode;
11  return head;
12}

Output: 10 -> null, then 10 -> 20 -> null, then 10 -> 20 -> 30 -> null.

The loop checks current.next != null, not current != null like printList. It must stop on the last node, so the next line can change that node's next. With current != null, the loop walks off the end, current becomes null, and current.next = newNode; throws a NullPointerException.

The empty-list check comes first for the same reason: when head is null, there is no node to walk from. That is also why addLast returns the head. The head changes only when the list was empty, and main saves it with head = addLast(head, ...).

Part 9 · Check yourself

Self-check

Not graded. Tap an answer to see if you got it, and read why.

  1. What does each node in a singly linked list store?

  2. To reach the 4th node, a linked list must…

  3. To insert X between B and C, which line must run first?

  4. What does previous.next = previous.next.next; do?

  5. After Node b = a; b.data = 9;, what is a.data?

  6. A photo viewer with Next and Previous buttons fits which kind of linked list?

  7. A traversal loop while (current != null) on a circular list will…

Score: 0 / 7

Key takeaways

  1. Each node holds a value and a reference to the next node. head refers to the first; the last one's next is null.
  2. Node b = a; copies the reference, not the node.
  3. Traversal follows the links. We cannot jump to a position.
  4. Insertion and deletion change links, not values. Connect the new node first.
  5. Singly goes one way, doubly goes both, circular loops back.
  6. Arrays reach faster. Linked lists edit faster, once you are there.

Next lesson: Stacks.

References

  1. A. Bhargava, Grokking Algorithms. Manning, 2016, Chapter 2.
  2. M. Reid-Miller, "Singly-Linked List Class" and "Doubly-Linked Lists," 15-121 lecture slides, Carnegie Mellon University, 2020.
  3. Oracle, "Types, Values, and Variables," The Java Language Specification, Java SE 21, Chapter 4. docs.oracle.com
  4. Programiz, "Linked List Data Structure" and "Types of Linked List." programiz.com/dsa
  5. ITC 120 Data Structures and Algorithms Syllabus, Faculty of Computing, Engineering, and Technology, Davao Oriental State University.