Skip to study material
← Question index

QUESTION 14

Explain circular singly linked lists and their operations.

5 marks

Answer in brief

A circular singly linked list forms a forward cycle through all its nodes.

Tail representation

With a non-empty tail pointer, the first node is tail->next. The only node in a one-node list points to itself. This representation gives convenient access to both the tail and the beginning without walking through the list.

Insertion

  1. For an empty list, make the new node link to itself and set tail to it.
  2. For a non-empty list, link new->next to tail->next and tail->next to new.
  3. For an append, also set tail = new; for a head insertion keep the old tail.

Traversal

For a non-empty list, save start = tail->next. Process nodes and move forward until the pointer returns to start. A do-while form expresses the first valid visit. Testing only for NULL would not stop a normal circular traversal.

Deletion

Handle an empty list separately. When removing the only node, free it and set tail = NULL. Otherwise bypass the target through its predecessor and update tail if the target was the tail. The resulting final link must still reach the current first node.

Uses and complexity

Circular lists suit round-robin scheduling and repeated cycling through participants. Head insertion or tail append with this representation needs O(1) link work; a value search can require O(n). Traversal visits each node once and uses O(1) auxiliary pointers. A broken termination rule can loop indefinitely.

Diagram or flowchart

CodeBhavya illustration of circular
Explain circular singly linked lists and their operations. · Download diagram

Complete C example

main.c

Download main.c
/* CodeBhavya | Data Structures AR25 | Learning example */
#include <stdio.h>
#include <stdlib.h>
struct Node { int data; struct Node *next; };
int append(struct Node **tail, int value)
{
    struct Node *node = malloc(sizeof *node);
    if (node == NULL) { return 0; }
    node->data = value;
    if (*tail == NULL) { node->next = node; }
    else { node->next = (*tail)->next; (*tail)->next = node; }
    *tail = node; return 1;
}
int remove_front(struct Node **tail, int *out)
{
    if (*tail == NULL) { return 0; }
    struct Node *first = (*tail)->next; *out = first->data;
    if (first == *tail) { *tail = NULL; }
    else { (*tail)->next = first->next; }
    free(first); return 1;
}
void display(const struct Node *tail)
{
    if (tail == NULL) { puts("Empty"); return; }
    const struct Node *first = tail->next, *p = first;
    do { printf("%d%s", p->data, p->next == first ? "\n" : " "); p = p->next; } while (p != first);
}

int main(void)
{
    struct Node *tail = NULL; int value;
    for (int i = 10; i <= 30; i += 10) {
        if (!append(&tail, i)) {
            while (remove_front(&tail, &value)) { }
            puts("Allocation failed"); return 1;
        }
    }
    display(tail); remove_front(&tail, &value); display(tail);
    while (remove_front(&tail, &value)) { }
    return 0;
}

Sample input and output

The example uses values in the code.

Output

10 20 30
20 30