C Data Structures: Singly, Doubly & Circular Linked Lists Masterclass

โšก C (C17 / C23 Standard) ๐ŸŸข Lesson 47 ๐Ÿ“‚ Phase 18: Data Structures in C ๐Ÿ“… 2026 Comprehensive Master Edition
๐Ÿ“Œ Covered in this in-depth guide: Singly Linked List (create/insert/delete/search) ยท Doubly Linked List ยท Circular Linked List ยท Node struct with self-referential pointers ยท O(1) head insert ยท Reversing a list

Welcome to Phase 18 (Chapter 47): C Data Structures โ€” Singly, Doubly & Circular Linked Lists Masterclass! A linked list is a chain of heap-allocated Node structs, each holding data and a pointer to the next node. Unlike arrays, linked lists support O(1) head insertion and deletion without shifting elements.

1Linked List vs Array โ€” When to Choose
OperationArrayLinked List
Random Access (arr[i])O(1) โ€” Direct indexO(n) โ€” Must traverse from head
Head InsertO(n) โ€” Shift all elementsO(1) โ€” Reroute head pointer
Middle InsertO(n) โ€” Shift right halfO(n) traversal + O(1) rewire
Delete by valueO(n) shiftO(n) find + O(1) rewire
MemoryContiguous (cache-friendly)Scattered (heap fragmentation, pointer overhead)
Singly Linked List RAM Layout: head โ”‚ โ–ผ [data=10|next]โ”€โ”€โ–บ[data=20|next]โ”€โ”€โ–บ[data=30|next=NULL] 0x5000 0x5020 0x5040 Each node is a separate malloc() allocation on the HEAP.
2Complete Singly Linked List Implementation
C โ€” Full Singly Linked List (CRUD + Reverse)โ–ถ Try in Compiler
#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node *next;
} Node;

/* Insert at head โ€” O(1) */
Node *push_front(Node *head, int value) {
    Node *n = malloc(sizeof(Node));
    if (!n) { perror("malloc"); exit(1); }
    n->data = value;
    n->next = head;
    return n;
}

/* Insert at tail โ€” O(n) */
Node *push_back(Node *head, int value) {
    Node *n = malloc(sizeof(Node));
    if (!n) { perror("malloc"); exit(1); }
    n->data = value;
    n->next = NULL;
    if (!head) return n;
    Node *cur = head;
    while (cur->next) cur = cur->next;
    cur->next = n;
    return head;
}

/* Delete first node with given value โ€” O(n) */
Node *delete_value(Node *head, int value) {
    if (!head) return NULL;
    if (head->data == value) {
        Node *next = head->next;
        free(head);
        return next;
    }
    Node *cur = head;
    while (cur->next && cur->next->data != value)
        cur = cur->next;
    if (cur->next) {
        Node *to_del = cur->next;
        cur->next = to_del->next;
        free(to_del);
    }
    return head;
}

/* Reverse in-place โ€” O(n) */
Node *reverse(Node *head) {
    Node *prev = NULL, *curr = head, *next = NULL;
    while (curr) {
        next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
}

void print_list(const Node *head) {
    for (const Node *n = head; n; n = n->next)
        printf("%d -> ", n->data);
    printf("NULL\n");
}

void free_list(Node *head) {
    while (head) { Node *tmp = head->next; free(head); head = tmp; }
}

int main(void) {
    Node *list = NULL;
    list = push_back(list, 10);
    list = push_back(list, 20);
    list = push_back(list, 30);
    list = push_front(list, 5);
    printf("Original:  "); print_list(list);

    list = delete_value(list, 20);
    printf("Deleted 20: "); print_list(list);

    list = reverse(list);
    printf("Reversed:  "); print_list(list);

    free_list(list);
    return 0;
}
3Technical FAQs

Q1: What is a sentinel/dummy head node?

A dummy head node at index -1 simplifies insert/delete code by eliminating special-case handling for empty lists and head deletions.

Q2: How do you detect a cycle in a linked list?

Use Floyd's Cycle Detection (Tortoise & Hare): two pointers, slow moves 1 step, fast moves 2 steps. If they meet, a cycle exists. Time O(n), Space O(1).

Q3: What is a doubly linked list advantage?

Each node has both next and prev pointers, enabling O(1) backward traversal and O(1) deletion when given a pointer directly to the node.

Q4: When is a circular linked list useful?

In Round-Robin scheduling (OS process queues), music playlists that loop, and buffer ring implementations where the tail always connects back to the head.

Q5: How do you find the middle of a linked list?

Use the two-pointer technique: slow moves 1 step, fast moves 2 steps. When fast reaches the end, slow is at the middle. O(n) time, O(1) space.