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
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
#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