05 The Circular Linked List
1. The Concept & Purpose
What is it?
A list where the last node does not point to NULL. Instead, it points back to the Head (or the Sentinel).
* Visual: [Sentinel] -> [A] -> [B] -> [C] --(points back)--> [Sentinel]
Why introduce it? (The Logic)
1. Continuous Looping: Useful for applications that need to cycle through data repeatedly without resetting (e.g., Round-Robin process scheduling in Operating Systems, media players on "Repeat" mode).
2. Accessibility: From any node in the list, you can reach any other node just by keeping moving forward. You never hit a dead end (NULL).
2. Modifications Required
We assume a Singly Linked List with a Sentinel as the base.
A. Initialization (createList)
- Change: The Sentinel must point to itself, not
NULL. - Why: An empty circular list is just a Sentinel pointing to the Sentinel.
B. Insertion at Back (pushBack)
- Change: The new tail must point to the Sentinel, not
NULL.void pushBack(LinkedList* list, int val) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = val; // 1. New node points back to Head (Sentinel) newNode->next = list->head; // 2. Old tail points to New Node // (Assuming we have a 'tail' pointer for O(1) access) list->tail->next = newNode; list->tail = newNode; }
C. Traversal / Printing (The Critical Change)
- Change: You cannot use
while (p != NULL). That loop will run forever (Infinite Loop). - New Logic: You must stop when the pointer wraps around to the start.
3. Unique Precautions (Gotchas)
- The Infinite Loop Trap: This is the #1 bug. If you write
while(p)orwhile(p->next), your program will freeze. Always checkif (p == head). - Josephus Problem: When deleting nodes in a circle, be very careful not to delete the Sentinel if your logic assumes data nodes only.