Linked List in C

A Linked List is a linear dynamic data structure where elements (called nodes) are not stored in contiguous memory locations. Each node contains data and a pointer (link) to the next node.

Unlike arrays, linked lists can grow or shrink easily at runtime and do not require contiguous memory allocation.

• Dynamic size
• No random access (O(n) time)
• Efficient insertion/deletion (O(1) if position known)
• Extra memory for pointers

1. Self-Referential Structure for Linked List Node

C
Singly Linked List Node
typedef struct node {
    int data;
    struct node* next;
} Node;
Note: Most common & recommended way using typedef

2. Core Operations of Singly Linked List

OperationTime ComplexityDescription
Create/Insert at BeginningO(1)Fastest insertion
Insert at EndO(n) / O(1) with tailCommon when no tail pointer
Insert at PositionO(n)Need to traverse
Delete from BeginningO(1)Very fast
Delete from EndO(n)Need previous node
Delete by ValueO(n)Search + delete
Traverse/PrintO(n)Linear traversal
SearchO(n)No random access
ReverseO(n)Iterative or Recursive

3. Complete Singly Linked List Implementation

C
Full Singly Linked List with all basic operations
#include <stdio.h>
#include <stdlib.h>

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

// Function prototypes
Node* createNode(int data);
void insertAtBeginning(Node** head, int data);
void insertAtEnd(Node** head, int data);
void deleteNode(Node** head, int key);
void printList(Node* head);
void freeList(Node** head);

int main() {
    Node* head = NULL;

    insertAtBeginning(&head, 30);
    insertAtBeginning(&head, 20);
    insertAtEnd(&head, 40);
    insertAtBeginning(&head, 10);

    printf("Original List: ");
    printList(head);

    deleteNode(&head, 20);
    printf("After deleting 20: ");
    printList(head);

    freeList(&head);
    return 0;
}

Node* createNode(int data) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

void insertAtBeginning(Node** head, int data) {
    Node* newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

void insertAtEnd(Node** head, int data) {
    Node* newNode = createNode(data);
    if (*head == NULL) {
        *head = newNode;
        return;
    }
    Node* temp = *head;
    while (temp->next != NULL)
        temp = temp->next;
    temp->next = newNode;
}

void deleteNode(Node** head, int key) {
    Node* temp = *head;
    Node* prev = NULL;

    if (temp != NULL && temp->data == key) {
        *head = temp->next;
        free(temp);
        return;
    }

    while (temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    if (temp == NULL) return;

    prev->next = temp->next;
    free(temp);
}

void printList(Node* head) {
    Node* temp = head;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}

void freeList(Node** head) {
    Node* current = *head;
    Node* next;
    while (current != NULL) {
        next = current->next;
        free(current);
        current = next;
    }
    *head = NULL;
}

4. Array vs Linked List - Quick Comparison

FeatureArrayLinked List
Memory AllocationContiguousNon-contiguous
SizeFixed (static)Dynamic
Access ElementO(1)O(n)
Insert/Delete at BeginningO(n)O(1)
Insert/Delete at EndO(1) (if dynamic)O(n) without tail
Extra MemoryNoYes (pointers)

5. Next Steps / Advanced Topics

  • Doubly Linked List
  • Circular Linked List
  • Circular Doubly Linked List
  • Reverse a Linked List (Iterative + Recursive)
  • Find middle of Linked List (Fast-Slow pointer)
  • Detect Loop (Floyd’s Cycle Detection)
  • Merge two sorted Linked Lists
  • Polynomial representation using Linked List