Linked Lists in C
Learn the fundamental data structure of linked lists. Create singly linked lists, doubly linked lists, and perform operations like insertion, deletion, and traversal.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Understand what linked lists are and why they are useful
- ✓Create and traverse a singly linked list
- ✓Insert and delete nodes at different positions
- ✓Implement a doubly linked list
- ✓Compare linked lists vs arrays
01What is a Linked List?
A linked list is a linear data structure where elements (called nodes) are connected using pointers. Unlike arrays, linked list elements are not stored in contiguous memory locations.
Why Use Linked Lists?
Dynamic Size
Grow or shrink as needed - no fixed size
Easy Insertion/Deletion
O(1) insertion at head, no shifting needed
Memory Efficient
Allocate memory only when needed
Foundation for Other Structures
Stacks, queues, graphs use linked lists
Linked List Structure
Each node contains data and a pointer to the next node
02Defining a Node
A node is a structure containing two parts: the data and a pointer to the next node.
1// Define a node structure2struct Node {3 int data; // The actual data4 struct Node* next; // Pointer to the next node5};67// Using typedef for cleaner syntax8typedef struct Node {9 int data;10 struct Node* next;11} Node;Self-referential structure: The node structure contains a pointer to itself (struct Node*). This is how nodes link to each other!
03Creating and Linking Nodes
1#include <stdio.h>2#include <stdlib.h>34typedef struct Node {5 int data;6 struct Node* next;7} Node;89// Function to create a new node10Node* createNode(int data) {11 Node* newNode = (Node*)malloc(sizeof(Node));12 if (newNode == NULL) {13 printf("Memory allocation failed!\n");14 exit(1);15 }16 newNode->data = data;17 newNode->next = NULL;18 return newNode;19}2021int main() {22 // Create three nodes23 Node* head = createNode(10);24 Node* second = createNode(20);25 Node* third = createNode(30);26 27 // Link them together28 head->next = second;29 second->next = third;30 // third->next is already NULL31 32 // Traverse and print33 Node* current = head;34 while (current != NULL) {35 printf("%d -> ", current->data);36 current = current->next;37 }38 printf("NULL\n");39 40 // Free memory41 free(head);42 free(second);43 free(third);44 45 return 0;46}Expected Output:
04Insertion Operations
Insert at Beginning (Push)
1// Insert at the beginning - O(1) time complexity2void insertAtBeginning(Node** head, int data) {3 Node* newNode = createNode(data);4 newNode->next = *head; // New node points to current head5 *head = newNode; // Head now points to new node6}78// Usage:9// Node* head = NULL;10// insertAtBeginning(&head, 30); // List: 3011// insertAtBeginning(&head, 20); // List: 20 -> 3012// insertAtBeginning(&head, 10); // List: 10 -> 20 -> 30Insert at End (Append)
1// Insert at the end - O(n) time complexity2void insertAtEnd(Node** head, int data) {3 Node* newNode = createNode(data);4 5 // If list is empty, new node becomes head6 if (*head == NULL) {7 *head = newNode;8 return;9 }10 11 // Traverse to the last node12 Node* current = *head;13 while (current->next != NULL) {14 current = current->next;15 }16 17 // Link last node to new node18 current->next = newNode;19}Insert After a Node
1// Insert after a given node - O(1) time complexity2void insertAfter(Node* prevNode, int data) {3 if (prevNode == NULL) {4 printf("Previous node cannot be NULL\n");5 return;6 }7 8 Node* newNode = createNode(data);9 newNode->next = prevNode->next;10 prevNode->next = newNode;11}05Deletion Operations
1// Delete a node by value2void deleteNode(Node** head, int key) {3 Node* temp = *head;4 Node* prev = NULL;5 6 // If head contains the key7 if (temp != NULL && temp->data == key) {8 *head = temp->next;9 free(temp);10 return;11 }12 13 // Search for the key14 while (temp != NULL && temp->data != key) {15 prev = temp;16 temp = temp->next;17 }18 19 // Key not found20 if (temp == NULL) {21 printf("Key %d not found\n", key);22 return;23 }24 25 // Unlink the node and free memory26 prev->next = temp->next;27 free(temp);28}2930// Delete the entire list31void deleteList(Node** head) {32 Node* current = *head;33 Node* next;34 35 while (current != NULL) {36 next = current->next;37 free(current);38 current = next;39 }40 41 *head = NULL;42}Memory leaks: Always free() nodes when deleting them. Forgetting to free causes memory leaks!
06Traversal and Search
1// Print all elements2void printList(Node* head) {3 Node* current = head;4 while (current != NULL) {5 printf("%d -> ", current->data);6 current = current->next;7 }8 printf("NULL\n");9}1011// Count nodes12int countNodes(Node* head) {13 int count = 0;14 Node* current = head;15 while (current != NULL) {16 count++;17 current = current->next;18 }19 return count;20}2122// Search for a value23int search(Node* head, int key) {24 Node* current = head;25 int position = 0;26 27 while (current != NULL) {28 if (current->data == key) {29 return position; // Found at this position30 }31 current = current->next;32 position++;33 }34 35 return -1; // Not found36}07Doubly Linked List
A doubly linked list has nodes with pointers to both the next and previous nodes, allowing bidirectional traversal.
1typedef struct DNode {2 int data;3 struct DNode* prev; // Pointer to previous node4 struct DNode* next; // Pointer to next node5} DNode;67// Create a new doubly linked node8DNode* createDNode(int data) {9 DNode* newNode = (DNode*)malloc(sizeof(DNode));10 newNode->data = data;11 newNode->prev = NULL;12 newNode->next = NULL;13 return newNode;14}1516// Insert at beginning of doubly linked list17void insertAtBeginningDL(DNode** head, int data) {18 DNode* newNode = createDNode(data);19 20 newNode->next = *head;21 22 if (*head != NULL) {23 (*head)->prev = newNode;24 }25 26 *head = newNode;27}2829// Traverse forward30void printForward(DNode* head) {31 DNode* current = head;32 printf("Forward: ");33 while (current != NULL) {34 printf("%d <-> ", current->data);35 current = current->next;36 }37 printf("NULL\n");38}3940// Traverse backward (from tail)41void printBackward(DNode* tail) {42 DNode* current = tail;43 printf("Backward: ");44 while (current != NULL) {45 printf("%d <-> ", current->data);46 current = current->prev;47 }48 printf("NULL\n");49}08Arrays vs Linked Lists
| Feature | Array | Linked List |
|---|---|---|
| Memory | Contiguous | Non-contiguous |
| Size | Fixed (or reallocate) | Dynamic |
| Access | O(1) random access | O(n) sequential |
| Insert at start | O(n) - shift elements | O(1) |
| Insert at end | O(1) if space, O(n) if resize | O(n) or O(1) with tail |
| Memory overhead | None | Extra pointer per node |
| Cache performance | Excellent | Poor |
09Summary
Key Concepts
- * Nodes contain data + pointer to next
- * Head pointer tracks the first node
- * Last node points to NULL
- * Dynamic memory with malloc/free
Operations
- * Insert: beginning O(1), end O(n)
- * Delete: O(n) search + O(1) remove
- * Search: O(n) linear
- * Traverse: O(n)
Test Your Knowledge
Related Tutorials
Pointers in C
The most powerful feature in C! Pointers store memory addresses. Learn what they are, why they matter, and how to use them safely.
Structures in C
Group related data together! Create your own data types with struct. Store a student's name, age, and grade in one variable.
Dynamic Memory Allocation
Allocate memory at runtime! Use malloc, calloc, realloc, and free. Create arrays whose size you don't know until the program runs.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!