Theory
The roster closes the circle
Final BookBridge build: the reading-room roster. Four members share 2 desks; after Zoya's turn the roster hands the desk back to Riya. Forever.
Last lesson's IssueList cannot express this: its tail says null, full stop. Today the tail says "go back to the start", and every operation must respect one new reality: there is no null to lean on. Create, traverse, insert, delete: same 4 verbs, rewired for a world without an end.
Theory
One clever choice before any code
Which node should the class remember? Instinct says the head. The professionals keep the last node instead, and it buys 2 ends for the price of 1:
- the head is always reachable instantly:
last.next - the tail is
lastitself
So inserting at the FRONT and at the END both need no walking at all: both happen where last already stands. A singly list offering that would have to walk its whole chain for every append.
Practical
The roster, wired as a circle
class CNode {
String name;
CNode next;
CNode(String n) { name = n; }
}
class Roster {
CNode last; // last.next IS the head
void addLast(String name) { // join at the end of the circle
CNode n = new CNode(name);
if (last == null) {
last = n;
n.next = n; // points at ITSELF: smallest circle
} else {
n.next = last.next; // 1: n grabs the head
last.next = n; // 2: old last points at n
last = n; // 3: n becomes the new last
}
}
void traverse() { // print each member exactly once
if (last == null) return;
CNode cur = last.next; // start at the head
do {
System.out.println(cur.name);
cur = cur.next;
} while (cur != last.next); // stop when the head reappears
}
void deleteFirst() { // the head leaves the circle
if (last == null) return;
if (last.next == last) { last = null; return; } // only node
last.next = last.next.next; // bypass the head
}
}
Theory
Trace: the circle grows
addLast("Riya") on empty: last = Riya, and Riya.next = Riya. One node, pointing at itself: a complete, legal circle.
addLast("Aman"): step 1, Aman.next = last.next (= Riya, the head); step 2, Riya.next = Aman; step 3, last = Aman.
Circle: Riya → Aman → Riya...
addLast("Zoya"): Zoya.next = Riya; Aman.next = Zoya; last = Zoya.
Circle: Riya → Aman → Zoya → back to Riya. traverse() starts at last.next (Riya) and prints Riya, Aman, Zoya, then meets Riya again and stops.
Quiz
In the Roster class, what does the very FIRST node's next point to, immediately after addLast("Riya") on an empty roster?
- null, until a second member joins
- The node itself: Riya.next == Riya
- The last reference of the Roster object
- It is left unassigned, so reading it is a compile error
Show the answer
The node itself: Riya.next == Riya
A circular list must ALWAYS close its circle, even with one member: n.next = n makes the smallest possible loop, so traverse and every other operation work without special-casing "circle of 1". Option A would make it a singly list and instantly break the do-while (it would walk into null). Option C confuses a field of the Roster with a node in the chain. Option D forgets Unit 2: fields default to null, and the constructor here explicitly assigns next anyway.
Think first
Trace the exit
Roster: Riya → Aman → Zoya (last = Zoya). Call deleteFirst(), then traverse(). Walk every reference before tapping: who is printed, and what does Zoya.next hold now?
Show the answer
deleteFirst runs last.next = last.next.next: Zoya.next was Riya, Riya.next is Aman, so Zoya.next = Aman. Riya has no incoming reference left: garbage-collected. The circle is Aman → Zoya → Aman, and traverse prints Aman, Zoya. Note what never happened: no walking, no null checks, one reassignment. And if the roster had held only Riya, the guard last.next == last would have fired and set last = null: the circle of 1 empties to nothing.
Watch out
Circle-specific traps
while (cur != null): loops forever; no next in a healthy circle is ever null. The stop test is positional: back at the start.
Plain while instead of do-while: while (cur != last.next) is false before the first print (cur IS the head), so nothing prints. The body-first loop is not optional here.
Deleting last itself: bypassing is not enough; last must move to the node BEFORE it, and finding that node in a singly circle means walking almost all the way around.
Theory
BookBridge, complete
Step back and look at what the semester built: one console app that grew variables into a Book class, a Person family with polymorphism, guarded Strings and a custom exception, a background reminder thread, shelved packages, and now 2 hand-built lists running its queues. That is BCA403's whole syllabus living in one program. The circular pattern itself returns wherever turns repeat: BCA203's round-robin scheduler, playlists on repeat, and multiplayer game loops.
Summary
Key takeaways
- Keep a reference to the LAST node: last.next is the head, so both ends are reachable without walking.
- First node of a circle points at itself: n.next = n.
- Insert at end: n.next = last.next, last.next = n, last = n (front insert: same 2 rewires, skip moving last).
- Traverse with do-while from last.next, stopping when the head reappears; while-null never terminates.
- deleteFirst: last.next = last.next.next; a single-node circle empties to last = null.
- Deleting last itself means walking to its predecessor and moving last there.
- Memory hook: the circle of one points at itself; the loop that waits for null waits forever.